mirror of
https://github.com/logto-io/logto.git
synced 2025-02-17 22:04:19 -05:00
feat(core): undeploy worker scripts when jwt customizer is deleted (#5685)
undeloy work scripts when the jwt customizer is deleted
This commit is contained in:
parent
9b3d4ef75b
commit
543931aa88
6 changed files with 68 additions and 15 deletions
|
@ -2,6 +2,8 @@ import { GlobalValues } from '@logto/shared';
|
|||
import { createMockUtils } from '@logto/shared/esm';
|
||||
import nock from 'nock';
|
||||
|
||||
import { mockLogtoConfigsLibrary } from '#src/test-utils/mock-libraries.js';
|
||||
|
||||
import { type LogtoConfigLibrary } from './logto-config.js';
|
||||
|
||||
const { jest } = import.meta;
|
||||
|
@ -28,17 +30,12 @@ await mockEsmWithActual('#src/env-set/index.js', () => ({
|
|||
const { createCloudConnectionLibrary } = await import('./cloud-connection.js');
|
||||
|
||||
const logtoConfigs: LogtoConfigLibrary = {
|
||||
...mockLogtoConfigsLibrary,
|
||||
getCloudConnectionData: jest.fn().mockResolvedValue({
|
||||
appId: 'appId',
|
||||
appSecret: 'appSecret',
|
||||
resource: 'resource',
|
||||
}),
|
||||
getOidcConfigs: jest.fn(),
|
||||
upsertJwtCustomizer: jest.fn(),
|
||||
getJwtCustomizer: jest.fn(),
|
||||
getJwtCustomizers: jest.fn(),
|
||||
updateJwtCustomizer: jest.fn(),
|
||||
deployJwtCustomizerScript: jest.fn(),
|
||||
};
|
||||
|
||||
describe('getAccessToken()', () => {
|
||||
|
|
|
@ -8,6 +8,7 @@ import {
|
|||
jwtCustomizerConfigGuard,
|
||||
logtoOidcConfigGuard,
|
||||
} from '@logto/schemas';
|
||||
import { assert } from '@silverhand/essentials';
|
||||
import chalk from 'chalk';
|
||||
import { ZodError, z } from 'zod';
|
||||
|
||||
|
@ -173,6 +174,36 @@ export const createLogtoConfigLibrary = ({
|
|||
});
|
||||
};
|
||||
|
||||
const undeployJwtCustomizerScript = async <T extends LogtoJwtTokenKey>(
|
||||
cloudConnection: CloudConnectionLibrary,
|
||||
key: T
|
||||
) => {
|
||||
const [client, jwtCustomizers] = await Promise.all([
|
||||
cloudConnection.getClient(),
|
||||
getJwtCustomizers(),
|
||||
]);
|
||||
|
||||
assert(jwtCustomizers[key], new RequestError({ code: 'entity.not_exists', key }));
|
||||
|
||||
// Undeploy the worker directly if the only JWT customizer is being deleted.
|
||||
if (Object.entries(jwtCustomizers).length === 1) {
|
||||
await client.delete(`/api/services/custom-jwt/worker`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove the JWT customizer script from the existing JWT customizer scripts and redeploy.
|
||||
const customizerScriptsFromDatabase = getJwtCustomizerScripts(jwtCustomizers);
|
||||
|
||||
await client.put(`/api/services/custom-jwt/worker`, {
|
||||
body: {
|
||||
production: {
|
||||
...customizerScriptsFromDatabase,
|
||||
[key]: undefined,
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
getOidcConfigs,
|
||||
getCloudConnectionData,
|
||||
|
@ -181,5 +212,6 @@ export const createLogtoConfigLibrary = ({
|
|||
getJwtCustomizers,
|
||||
updateJwtCustomizer,
|
||||
deployJwtCustomizerScript,
|
||||
undeployJwtCustomizerScript,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -11,6 +11,7 @@ import {
|
|||
} from '#src/__mocks__/index.js';
|
||||
import RequestError from '#src/errors/RequestError/index.js';
|
||||
import { ssoConnectorFactories } from '#src/sso/index.js';
|
||||
import { mockLogtoConfigsLibrary } from '#src/test-utils/mock-libraries.js';
|
||||
|
||||
import { createCloudConnectionLibrary } from '../cloud-connection.js';
|
||||
import { createConnectorLibrary } from '../connector.js';
|
||||
|
@ -51,17 +52,12 @@ const connectorLibrary = createConnectorLibrary(queries, {
|
|||
getClient: jest.fn(),
|
||||
});
|
||||
const cloudConnection = createCloudConnectionLibrary({
|
||||
...mockLogtoConfigsLibrary,
|
||||
getCloudConnectionData: jest.fn().mockResolvedValue({
|
||||
appId: 'appId',
|
||||
appSecret: 'appSecret',
|
||||
resource: 'resource',
|
||||
}),
|
||||
getOidcConfigs: jest.fn(),
|
||||
upsertJwtCustomizer: jest.fn(),
|
||||
getJwtCustomizer: jest.fn(),
|
||||
getJwtCustomizers: jest.fn(),
|
||||
updateJwtCustomizer: jest.fn(),
|
||||
deployJwtCustomizerScript: jest.fn(),
|
||||
});
|
||||
|
||||
const getLogtoConnectors = jest.spyOn(connectorLibrary, 'getLogtoConnectors');
|
||||
|
|
|
@ -24,6 +24,7 @@ const logtoConfigLibraries = {
|
|||
getJwtCustomizers: jest.fn(),
|
||||
updateJwtCustomizer: jest.fn(),
|
||||
deployJwtCustomizerScript: jest.fn(),
|
||||
undeployJwtCustomizerScript: jest.fn(),
|
||||
};
|
||||
|
||||
const settingRoutes = await pickDefault(import('./index.js'));
|
||||
|
@ -126,6 +127,10 @@ describe('configs JWT customizer routes', () => {
|
|||
|
||||
it('DELETE /configs/jwt-customizer/:tokenType should delete the record', async () => {
|
||||
const response = await routeRequester.delete('/configs/jwt-customizer/client-credentials');
|
||||
expect(logtoConfigLibraries.undeployJwtCustomizerScript).toHaveBeenCalledWith(
|
||||
tenantContext.cloudConnection,
|
||||
LogtoJwtTokenKey.ClientCredentials
|
||||
);
|
||||
expect(logtoConfigQueries.deleteJwtCustomizer).toHaveBeenCalledWith(
|
||||
LogtoJwtTokenKey.ClientCredentials
|
||||
);
|
||||
|
|
|
@ -40,6 +40,7 @@ export default function logtoConfigJwtCustomizerRoutes<T extends AuthedRouter>(
|
|||
getJwtCustomizers,
|
||||
updateJwtCustomizer,
|
||||
deployJwtCustomizerScript,
|
||||
undeployJwtCustomizerScript,
|
||||
} = logtoConfigs;
|
||||
|
||||
router.put(
|
||||
|
@ -177,15 +178,23 @@ export default function logtoConfigJwtCustomizerRoutes<T extends AuthedRouter>(
|
|||
status: [204, 404],
|
||||
}),
|
||||
async (ctx, next) => {
|
||||
const { isIntegrationTest } = EnvSet.values;
|
||||
|
||||
const {
|
||||
params: { tokenTypePath },
|
||||
} = ctx.guard;
|
||||
|
||||
await deleteJwtCustomizer(
|
||||
const tokenKey =
|
||||
tokenTypePath === LogtoJwtTokenKeyType.AccessToken
|
||||
? LogtoJwtTokenKey.AccessToken
|
||||
: LogtoJwtTokenKey.ClientCredentials
|
||||
);
|
||||
: LogtoJwtTokenKey.ClientCredentials;
|
||||
|
||||
// Undeploy the script first to avoid the case where the JWT customizer was deleted from DB but worker script not updated successfully.
|
||||
if (!isIntegrationTest) {
|
||||
await undeployJwtCustomizerScript(cloudConnection, tokenKey);
|
||||
}
|
||||
|
||||
await deleteJwtCustomizer(tokenKey);
|
||||
ctx.status = 204;
|
||||
return next();
|
||||
}
|
||||
|
|
14
packages/core/src/test-utils/mock-libraries.ts
Normal file
14
packages/core/src/test-utils/mock-libraries.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
import { type LogtoConfigLibrary } from '#src/libraries/logto-config.js';
|
||||
|
||||
const { jest } = import.meta;
|
||||
|
||||
export const mockLogtoConfigsLibrary: LogtoConfigLibrary = {
|
||||
getCloudConnectionData: jest.fn(),
|
||||
getOidcConfigs: jest.fn(),
|
||||
upsertJwtCustomizer: jest.fn(),
|
||||
getJwtCustomizer: jest.fn(),
|
||||
getJwtCustomizers: jest.fn(),
|
||||
updateJwtCustomizer: jest.fn(),
|
||||
deployJwtCustomizerScript: jest.fn(),
|
||||
undeployJwtCustomizerScript: jest.fn(),
|
||||
};
|
Loading…
Add table
Reference in a new issue