From b9ea24be8d2b63a7fdff8d33e81f707465f4322e Mon Sep 17 00:00:00 2001 From: Tymoteusz Czech <2625371+Tymek@users.noreply.github.com> Date: Fri, 16 Aug 2024 10:58:44 +0200 Subject: [PATCH] fix: orphaned token label only for items without projects (#7901) Orphaned token label was incorrectly assigned. Co-authored-by: Thomas Heartman --- .../ApiTokenIcon/ApiTokenIcon.test.tsx | 83 ++++++++++++++++--- .../apiToken/ApiTokenIcon/ApiTokenIcon.tsx | 19 ++++- .../common/ApiTokenTable/useApiTokenTable.tsx | 6 +- 3 files changed, 91 insertions(+), 17 deletions(-) diff --git a/frontend/src/component/admin/apiToken/ApiTokenIcon/ApiTokenIcon.test.tsx b/frontend/src/component/admin/apiToken/ApiTokenIcon/ApiTokenIcon.test.tsx index 3f0e7f924d..73f9ec6680 100644 --- a/frontend/src/component/admin/apiToken/ApiTokenIcon/ApiTokenIcon.test.tsx +++ b/frontend/src/component/admin/apiToken/ApiTokenIcon/ApiTokenIcon.test.tsx @@ -1,7 +1,68 @@ import { render } from 'utils/testRenderer'; import { screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import { ApiTokenIcon } from './ApiTokenIcon'; +import { ApiTokenIcon, isOrphanedToken } from './ApiTokenIcon'; + +describe('isOrphanedToken', () => { + it('should be true for wildcard tokens with secret indicating it is orphaned', () => { + expect( + isOrphanedToken({ + secret: '[]:development.be7536c3a160ff15e3a92da45de531dd54bc1ae15d8455c0476f086b', + projects: ['*'], + project: '*', + }), + ).toBe(true); + expect( + isOrphanedToken({ + secret: 'test:development.be7536c3a160ff15e3a92da45de531dd54bc1ae15d8455c0476f086b', + projects: ['*'], + project: '*', + }), + ).toBe(true); + }); + + it('should be false for true wildcard tokens', () => { + expect( + isOrphanedToken({ + secret: '*:development.be7536c3a160ff15e3a92da45de531dd54bc1ae15d8455c0476f086b', + projects: ['*'], + project: '*', + }), + ).toBe(false); + }); + + it('should be false for secrets in v1 format', () => { + expect( + isOrphanedToken({ + secret: 'be44368985f7fb3237c584ef86f3d6bdada42ddbd63a019d26955178', + projects: ['*'], + project: '*', + }), + ).toBe(false); + }); + + it('should be false if there are projects assigned to a token', () => { + expect( + isOrphanedToken({ + secret: 'test:development.be7536c3a160ff15e3a92da45de531dd54bc1ae15d8455c0476f086b', + projects: ['test'], + project: 'test', + }), + ).toBe(false); + expect( + isOrphanedToken({ + secret: '[]:development.be7536c3a160ff15e3a92da45de531dd54bc1ae15d8455c0476f086b', + projects: ['a', 'b'], + }), + ).toBe(false); + expect( + isOrphanedToken({ + secret: '[]:development.be7536c3a160ff15e3a92da45de531dd54bc1ae15d8455c0476f086b', + projects: ['a'], + }), + ).toBe(false); + }); +}); describe('ApiTokenIcon', () => { it('should show warning icon if it is an orphaned token', async () => { @@ -16,7 +77,10 @@ describe('ApiTokenIcon', () => { it('should show tooltip with warning message if it is an orphaned token', async () => { const user = userEvent.setup(); render( - , + , ); const errorIcon = await screen.findByTestId('orphaned-token-icon'); @@ -26,18 +90,13 @@ describe('ApiTokenIcon', () => { expect(tooltip).toHaveTextContent(/orphaned token/); }); - it('should not show warning icon if token is in v1 format', async () => { - render( - , - ); - - const errorIcon = await screen.queryByTestId('orphaned-token-icon'); - expect(errorIcon).toBeNull(); - }); - it('should not show warning for true wildcard tokens', async () => { render( - , + , ); const errorIcon = await screen.queryByTestId('orphaned-token-icon'); diff --git a/frontend/src/component/admin/apiToken/ApiTokenIcon/ApiTokenIcon.tsx b/frontend/src/component/admin/apiToken/ApiTokenIcon/ApiTokenIcon.tsx index ab828d3b38..3f1df514f5 100644 --- a/frontend/src/component/admin/apiToken/ApiTokenIcon/ApiTokenIcon.tsx +++ b/frontend/src/component/admin/apiToken/ApiTokenIcon/ApiTokenIcon.tsx @@ -11,12 +11,23 @@ interface IApiTokenIconProps { secret?: string; } -export const ApiTokenIcon: FC = ({ secret }) => { +export const isOrphanedToken = ({ + secret, + project, + projects, +}: IApiTokenIconProps): boolean => { const tokenFormat = secret?.includes(':') ? 'v2' : 'v1'; // see https://docs.getunleash.io/reference/api-tokens-and-client-keys#format - const isWildcardToken = secret?.startsWith('*:'); - const isOrphanedToken = tokenFormat === 'v2' && !isWildcardToken; + const isWildcardSecret = secret?.startsWith('*:'); + const hasProjects = + (projects && projects?.length > 1) || + (projects?.length === 1 && projects[0] !== '*') || + (project && project !== '*'); - if (isOrphanedToken) { + return tokenFormat === 'v2' && !isWildcardSecret && !hasProjects; +}; + +export const ApiTokenIcon: FC = ({ ...props }) => { + if (isOrphanedToken(props)) { return ( ( - + ), disableSortBy: true, disableGlobalFilter: true,