improvement: move unique name constraint to db for secret syncs and app connections

This commit is contained in:
Scott Wilson
2025-02-03 19:36:37 -08:00
parent 110d0e95b0
commit 1ba0b9c204
3 changed files with 149 additions and 212 deletions
@@ -144,22 +144,6 @@ export const appConnectionServiceFactory = ({
OrgPermissionSubjects.AppConnections OrgPermissionSubjects.AppConnections
); );
const appConnection = await appConnectionDAL.transaction(async (tx) => {
const isConflictingName = Boolean(
await appConnectionDAL.findOne(
{
name: params.name,
orgId: actor.orgId
},
tx
)
);
if (isConflictingName)
throw new BadRequestError({
message: `An App Connection with the name "${params.name}" already exists`
});
const validatedCredentials = await validateAppConnectionCredentials({ const validatedCredentials = await validateAppConnectionCredentials({
app, app,
credentials, credentials,
@@ -173,25 +157,27 @@ export const appConnectionServiceFactory = ({
kmsService kmsService
}); });
const connection = await appConnectionDAL.create( try {
{ const connection = await appConnectionDAL.create({
orgId: actor.orgId, orgId: actor.orgId,
encryptedCredentials, encryptedCredentials,
method, method,
app, app,
...params ...params
}, });
tx
);
return { return {
...connection, ...connection,
credentialsHash: generateHash(connection.encryptedCredentials), credentialsHash: generateHash(connection.encryptedCredentials),
credentials: validatedCredentials credentials: validatedCredentials
}; } as TAppConnection;
}); } catch (err) {
if (err instanceof DatabaseError && (err.error as { code: string })?.code === "23505") {
throw new BadRequestError({ message: `An App Connection with the name "${params.name}" already exists` });
}
return appConnection as TAppConnection; throw err;
}
}; };
const updateAppConnection = async ( const updateAppConnection = async (
@@ -215,24 +201,6 @@ export const appConnectionServiceFactory = ({
OrgPermissionSubjects.AppConnections OrgPermissionSubjects.AppConnections
); );
const updatedAppConnection = await appConnectionDAL.transaction(async (tx) => {
if (params.name && appConnection.name !== params.name) {
const isConflictingName = Boolean(
await appConnectionDAL.findOne(
{
name: params.name,
orgId: appConnection.orgId
},
tx
)
);
if (isConflictingName)
throw new BadRequestError({
message: `An App Connection with the name "${params.name}" already exists`
});
}
let encryptedCredentials: undefined | Buffer; let encryptedCredentials: undefined | Buffer;
if (credentials) { if (credentials) {
@@ -267,20 +235,21 @@ export const appConnectionServiceFactory = ({
}); });
} }
const updatedConnection = await appConnectionDAL.updateById( try {
connectionId, const updatedConnection = await appConnectionDAL.updateById(connectionId, {
{
orgId: actor.orgId, orgId: actor.orgId,
encryptedCredentials, encryptedCredentials,
...params ...params
},
tx
);
return updatedConnection;
}); });
return decryptAppConnection(updatedAppConnection, kmsService); return await decryptAppConnection(updatedConnection, kmsService);
} catch (err) {
if (err instanceof DatabaseError && (err.error as { code: string })?.code === "23505") {
throw new BadRequestError({ message: `An App Connection with the name "${params.name}" already exists` });
}
throw err;
}
}; };
const deleteAppConnection = async (app: AppConnection, connectionId: string, actor: OrgServiceActor) => { const deleteAppConnection = async (app: AppConnection, connectionId: string, actor: OrgServiceActor) => {
@@ -123,7 +123,6 @@ export const secretSyncDALFactory = (
}; };
const create = async (data: Parameters<(typeof secretSyncOrm)["create"]>[0]) => { const create = async (data: Parameters<(typeof secretSyncOrm)["create"]>[0]) => {
try {
const secretSync = (await secretSyncOrm.transaction(async (tx) => { const secretSync = (await secretSyncOrm.transaction(async (tx) => {
const sync = await secretSyncOrm.create(data, tx); const sync = await secretSyncOrm.create(data, tx);
@@ -139,13 +138,9 @@ export const secretSyncDALFactory = (
? await folderDAL.findSecretPathByFolderIds(secretSync.projectId, [secretSync.folderId]) ? await folderDAL.findSecretPathByFolderIds(secretSync.projectId, [secretSync.folderId])
: []; : [];
return expandSecretSync(secretSync, folderWithPath); return expandSecretSync(secretSync, folderWithPath);
} catch (error) {
throw new DatabaseError({ error, name: "Create - Secret Sync" });
}
}; };
const updateById = async (syncId: string, data: Parameters<(typeof secretSyncOrm)["updateById"]>[1]) => { const updateById = async (syncId: string, data: Parameters<(typeof secretSyncOrm)["updateById"]>[1]) => {
try {
const secretSync = (await secretSyncOrm.transaction(async (tx) => { const secretSync = (await secretSyncOrm.transaction(async (tx) => {
const sync = await secretSyncOrm.updateById(syncId, data, tx); const sync = await secretSyncOrm.updateById(syncId, data, tx);
@@ -161,9 +156,6 @@ export const secretSyncDALFactory = (
? await folderDAL.findSecretPathByFolderIds(secretSync.projectId, [secretSync.folderId]) ? await folderDAL.findSecretPathByFolderIds(secretSync.projectId, [secretSync.folderId])
: []; : [];
return expandSecretSync(secretSync, folderWithPath); return expandSecretSync(secretSync, folderWithPath);
} catch (error) {
throw new DatabaseError({ error, name: "Update by ID - Secret Sync" });
}
}; };
const findOne = async (filter: Parameters<(typeof secretSyncOrm)["findOne"]>[0], tx?: Knex) => { const findOne = async (filter: Parameters<(typeof secretSyncOrm)["findOne"]>[0], tx?: Knex) => {
@@ -8,7 +8,7 @@ import {
ProjectPermissionSub ProjectPermissionSub
} from "@app/ee/services/permission/project-permission"; } from "@app/ee/services/permission/project-permission";
import { KeyStorePrefixes, TKeyStoreFactory } from "@app/keystore/keystore"; import { KeyStorePrefixes, TKeyStoreFactory } from "@app/keystore/keystore";
import { BadRequestError, NotFoundError } from "@app/lib/errors"; import { BadRequestError, DatabaseError, NotFoundError } from "@app/lib/errors";
import { OrgServiceActor } from "@app/lib/types"; import { OrgServiceActor } from "@app/lib/types";
import { TAppConnectionServiceFactory } from "@app/services/app-connection/app-connection-service"; import { TAppConnectionServiceFactory } from "@app/services/app-connection/app-connection-service";
import { TProjectBotServiceFactory } from "@app/services/project-bot/project-bot-service"; import { TProjectBotServiceFactory } from "@app/services/project-bot/project-bot-service";
@@ -197,37 +197,26 @@ export const secretSyncServiceFactory = ({
// validates permission to connect and app is valid for sync destination // validates permission to connect and app is valid for sync destination
await appConnectionService.connectAppConnectionById(destinationApp, params.connectionId, actor); await appConnectionService.connectAppConnectionById(destinationApp, params.connectionId, actor);
const secretSync = await secretSyncDAL.transaction(async (tx) => { try {
const isConflictingName = Boolean( const secretSync = await secretSyncDAL.create({
(
await secretSyncDAL.find(
{
name: params.name,
projectId
},
tx
)
).length
);
if (isConflictingName)
throw new BadRequestError({
message: `A Secret Sync with the name "${params.name}" already exists for the project with ID "${folder.projectId}"`
});
const sync = await secretSyncDAL.create({
folderId: folder.id, folderId: folder.id,
...params, ...params,
...(params.isAutoSyncEnabled && { syncStatus: SecretSyncStatus.Pending }), ...(params.isAutoSyncEnabled && { syncStatus: SecretSyncStatus.Pending }),
projectId projectId
}); });
return sync;
});
if (secretSync.isAutoSyncEnabled) await secretSyncQueue.queueSecretSyncSyncSecretsById({ syncId: secretSync.id }); if (secretSync.isAutoSyncEnabled) await secretSyncQueue.queueSecretSyncSyncSecretsById({ syncId: secretSync.id });
return secretSync as TSecretSync; return secretSync as TSecretSync;
} catch (err) {
if (err instanceof DatabaseError && (err.error as { code: string })?.code === "23505") {
throw new BadRequestError({
message: `A Secret Sync with the name "${params.name}" already exists for the project with ID "${folder.projectId}"`
});
}
throw err;
}
}; };
const updateSecretSync = async ( const updateSecretSync = async (
@@ -260,7 +249,6 @@ export const secretSyncServiceFactory = ({
message: `Secret sync with ID "${secretSync.id}" is not configured for ${SECRET_SYNC_NAME_MAP[destination]}` message: `Secret sync with ID "${secretSync.id}" is not configured for ${SECRET_SYNC_NAME_MAP[destination]}`
}); });
const updatedSecretSync = await secretSyncDAL.transaction(async (tx) => {
let { folderId } = secretSync; let { folderId } = secretSync;
if (params.connectionId) { if (params.connectionId) {
@@ -298,40 +286,28 @@ export const secretSyncServiceFactory = ({
folderId = newFolder.id; folderId = newFolder.id;
} }
if (params.name && secretSync.name !== params.name) {
const isConflictingName = Boolean(
(
await secretSyncDAL.find(
{
name: params.name,
projectId: secretSync.projectId
},
tx
)
).length
);
if (isConflictingName)
throw new BadRequestError({
message: `A Secret Sync with the name "${params.name}" already exists for project with ID "${secretSync.projectId}"`
});
}
const isAutoSyncEnabled = params.isAutoSyncEnabled ?? secretSync.isAutoSyncEnabled; const isAutoSyncEnabled = params.isAutoSyncEnabled ?? secretSync.isAutoSyncEnabled;
const updatedSync = await secretSyncDAL.updateById(syncId, { try {
const updatedSecretSync = await secretSyncDAL.updateById(syncId, {
...params, ...params,
...(isAutoSyncEnabled && folderId && { syncStatus: SecretSyncStatus.Pending }), ...(isAutoSyncEnabled && folderId && { syncStatus: SecretSyncStatus.Pending }),
folderId folderId
}); });
return updatedSync;
});
if (updatedSecretSync.isAutoSyncEnabled) if (updatedSecretSync.isAutoSyncEnabled)
await secretSyncQueue.queueSecretSyncSyncSecretsById({ syncId: secretSync.id }); await secretSyncQueue.queueSecretSyncSyncSecretsById({ syncId: secretSync.id });
return updatedSecretSync as TSecretSync; return updatedSecretSync as TSecretSync;
} catch (err) {
if (err instanceof DatabaseError && (err.error as { code: string })?.code === "23505") {
throw new BadRequestError({
message: `A Secret Sync with the name "${params.name}" already exists for the project with ID "${secretSync.projectId}"`
});
}
throw err;
}
}; };
const deleteSecretSync = async ( const deleteSecretSync = async (