diff --git a/backend-pg/src/ee/services/license/licence-fns.ts b/backend-pg/src/ee/services/license/licence-fns.ts index 98c98633d..4855e1b47 100644 --- a/backend-pg/src/ee/services/license/licence-fns.ts +++ b/backend-pg/src/ee/services/license/licence-fns.ts @@ -27,7 +27,7 @@ export const getDefaultOnPremFeatures = (): TFeatureSet => ({ status: null, trial_end: null, has_used_trial: true, - secretApproval: true, + secretApproval: false, secretRotation: true }); diff --git a/backend-pg/src/ee/services/secret-snapshot/secret-snapshot-service.ts b/backend-pg/src/ee/services/secret-snapshot/secret-snapshot-service.ts index d3e7311a5..d1e5bad6b 100644 --- a/backend-pg/src/ee/services/secret-snapshot/secret-snapshot-service.ts +++ b/backend-pg/src/ee/services/secret-snapshot/secret-snapshot-service.ts @@ -1,12 +1,15 @@ import { ForbiddenError } from "@casl/ability"; +import { TableName, TSecretTagJunctionInsert } from "@app/db/schemas"; import { BadRequestError, InternalServerError } from "@app/lib/errors"; import { groupBy } from "@app/lib/fn"; import { logger } from "@app/lib/logger"; import { TSecretDALFactory } from "@app/services/secret/secret-dal"; import { TSecretVersionDALFactory } from "@app/services/secret/secret-version-dal"; +import { TSecretVersionTagDALFactory } from "@app/services/secret/secret-version-tag-dal"; import { TSecretFolderDALFactory } from "@app/services/secret-folder/secret-folder-dal"; import { TSecretFolderVersionDALFactory } from "@app/services/secret-folder/secret-folder-version-dal"; +import { TSecretTagDALFactory } from "@app/services/secret-tag/secret-tag-dal"; import { TLicenseServiceFactory } from "../license/license-service"; import { TPermissionServiceFactory } from "../permission/permission-service"; @@ -31,6 +34,8 @@ type TSecretSnapshotServiceFactoryDep = { "findLatestVersionByFolderId" | "insertMany" >; secretDAL: Pick; + secretTagDAL: Pick; + secretVersionTagDAL: Pick; folderDAL: Pick< TSecretFolderDALFactory, "findById" | "findBySecretPath" | "delete" | "insertMany" @@ -50,7 +55,9 @@ export const secretSnapshotServiceFactory = ({ folderDAL, secretDAL, permissionService, - licenseService + licenseService, + secretTagDAL, + secretVersionTagDAL }: TSecretSnapshotServiceFactoryDep) => { const projectSecretSnapshotCount = async ({ environment, @@ -190,7 +197,11 @@ export const secretSnapshotServiceFactory = ({ folderVersion.map(({ name, id, latestFolderVersion }) => ({ envId: snapshot.envId, id, - version: latestFolderVersion + 1, + // this means don't bump up the version if not root folder + // because below ones can be same version as nothing changed + version: deletedTopLevelFolders[folderId] + ? latestFolderVersion + 1 + : latestFolderVersion, name, parentId: folderId })) @@ -208,17 +219,33 @@ export const secretSnapshotServiceFactory = ({ secretId, envId, id, + tags, ...el }) => ({ ...el, id: secretId, - version: latestSecretVersion + 1, + version: deletedTopLevelSecsGroupById[secretId] + ? latestSecretVersion + 1 + : latestSecretVersion, folderId }) ) ), tx ); + const secretTagsToBeInsert: TSecretTagJunctionInsert[] = []; + const secretVerTagToBeInsert: Record = {}; + rollbackSnaps.forEach(({ secretVersions }) => { + secretVersions.forEach((secVer) => { + secVer.tags.forEach((tag) => { + secretTagsToBeInsert.push({ secretsId: secVer.secretId, secret_tagsId: tag.id }); + if (!secretVerTagToBeInsert?.[secVer.secretId]) + secretVerTagToBeInsert[secVer.secretId] = []; + secretVerTagToBeInsert[secVer.secretId].push(tag.id); + }); + }); + }); + await secretTagDAL.saveTagsToSecret(secretTagsToBeInsert, tx); const folderVersions = await folderVersionDAL.insertMany( folders.map(({ version, name, id, envId }) => ({ name, @@ -232,6 +259,17 @@ export const secretSnapshotServiceFactory = ({ secrets.map(({ id, updatedAt, createdAt, ...el }) => ({ ...el, secretId: id })), tx ); + await secretVersionTagDAL.insertMany( + secretVersions.flatMap(({ secretId, id }) => + secretVerTagToBeInsert?.[secretId]?.length + ? secretVerTagToBeInsert[secretId].map((tagId) => ({ + [`${TableName.SecretTag}Id` as const]: tagId, + [`${TableName.SecretVersion}Id` as const]: id + })) + : [] + ), + tx + ); const newSnapshot = await snapshotDAL.create( { folderId: snapshot.folderId, diff --git a/backend-pg/src/ee/services/secret-snapshot/snapshot-dal.ts b/backend-pg/src/ee/services/secret-snapshot/snapshot-dal.ts index 2174d0410..66c72ca53 100644 --- a/backend-pg/src/ee/services/secret-snapshot/snapshot-dal.ts +++ b/backend-pg/src/ee/services/secret-snapshot/snapshot-dal.ts @@ -223,6 +223,16 @@ export const snapshotDALFactory = (db: TDbClient) => { `${TableName.SnapshotSecret}.secretVersionId`, `${TableName.SecretVersion}.id` ) + .leftJoin( + TableName.SecretVersionTag, + `${TableName.SecretVersionTag}.${TableName.SecretVersion}Id`, + `${TableName.SecretVersion}.id` + ) + .leftJoin( + TableName.SecretTag, + `${TableName.SecretVersionTag}.${TableName.SecretTag}Id`, + `${TableName.SecretTag}.id` + ) .leftJoin<{ latestSecretVersion: number }>( (tx || db)(TableName.SecretVersion) .groupBy("secretId") @@ -249,8 +259,14 @@ export const snapshotDALFactory = (db: TDbClient) => { db.ref("folderVerName").withSchema("parent"), db.ref("folderVerId").withSchema("parent"), db.ref("max").withSchema("secGroupByMaxVersion").as("latestSecretVersion"), - db.ref("max").withSchema("folderGroupByMaxVersion").as("latestFolderVersion") + db.ref("max").withSchema("folderGroupByMaxVersion").as("latestFolderVersion"), + db.ref("id").withSchema(TableName.SecretTag).as("tagId"), + db.ref("id").withSchema(TableName.SecretVersionTag).as("tagVersionId"), + db.ref("color").withSchema(TableName.SecretTag).as("tagColor"), + db.ref("slug").withSchema(TableName.SecretTag).as("tagSlug"), + db.ref("name").withSchema(TableName.SecretTag).as("tagName") ); + const formated = sqlNestRelationships({ data, key: "snapshotId", @@ -270,7 +286,20 @@ export const snapshotDALFactory = (db: TDbClient) => { mapper: (el) => ({ ...SecretVersionsSchema.parse(el), latestSecretVersion: el.latestSecretVersion - }) + }), + childrenMapper: [ + { + key: "tagVersionId", + label: "tags" as const, + mapper: ({ + tagId: id, + tagName: name, + tagSlug: slug, + tagColor: color, + tagVersionId: vId + }) => ({ id, name, slug, color, vId }) + } + ] }, { key: "folderVerId", diff --git a/backend-pg/src/lib/knex/join.ts b/backend-pg/src/lib/knex/join.ts index 4e1ab09a3..965fd3e95 100644 --- a/backend-pg/src/lib/knex/join.ts +++ b/backend-pg/src/lib/knex/join.ts @@ -122,7 +122,7 @@ export const sqlNestRelationships = < lookupTable.add(pk); } - sqlChildMapper(doc, recordsGroupedByPk, lookupTable, pk, "", childrenMapper); + sqlChildMapper(doc, recordsGroupedByPk, lookupTable, pk, pk, childrenMapper); }); return recordsOrder.map((pkId) => recordsGroupedByPk[pkId]); }; diff --git a/backend-pg/src/server/routes/index.ts b/backend-pg/src/server/routes/index.ts index f13409ac4..e054ace62 100644 --- a/backend-pg/src/server/routes/index.ts +++ b/backend-pg/src/server/routes/index.ts @@ -300,6 +300,8 @@ export const registerRoutes = async ( const projectRoleService = projectRoleServiceFactory({ permissionService, projectRoleDAL }); const snapshotService = secretSnapshotServiceFactory({ + permissionService, + licenseService, folderDAL, secretDAL, snapshotDAL, @@ -307,8 +309,8 @@ export const registerRoutes = async ( snapshotSecretDAL, secretVersionDAL, folderVersionDAL, - permissionService, - licenseService + secretTagDAL, + secretVersionTagDAL }); const webhookService = webhookServiceFactory({ permissionService, diff --git a/backend-pg/src/services/secret/secret-dal.ts b/backend-pg/src/services/secret/secret-dal.ts index 95b072c7c..27a7201f5 100644 --- a/backend-pg/src/services/secret/secret-dal.ts +++ b/backend-pg/src/services/secret/secret-dal.ts @@ -99,7 +99,8 @@ export const secretDALFactory = (db: TDbClient) => { .select(db.ref("color").withSchema(TableName.SecretTag).as("tagColor")) .select(db.ref("slug").withSchema(TableName.SecretTag).as("tagSlug")) .select(db.ref("name").withSchema(TableName.SecretTag).as("tagName")); - return sqlNestRelationships({ + console.log(JSON.stringify(secs, null, 4)); + const data = sqlNestRelationships({ data: secs, key: "id", parentMapper: (el) => SecretsSchema.parse(el), @@ -116,6 +117,8 @@ export const secretDALFactory = (db: TDbClient) => { } ] }); + console.log(JSON.stringify(data, null, 4)); + return data; } catch (error) { throw new DatabaseError({ error, name: "get all secret" }); } diff --git a/backend-pg/src/services/secret/secret-service.ts b/backend-pg/src/services/secret/secret-service.ts index eaf40e13b..8cf6a4a54 100644 --- a/backend-pg/src/services/secret/secret-service.ts +++ b/backend-pg/src/services/secret/secret-service.ts @@ -164,17 +164,19 @@ export const secretServiceFactory = ({ tags !== undefined ? { tags, secretId: newSecrets[i].id } : [] ); if (secsUpdatedTag.length) { - await secretTagDAL.deleteTagsManySecret( + const delTags = await secretTagDAL.deleteTagsManySecret( projectId, secsUpdatedTag.map(({ secretId }) => secretId), tx ); + console.log(delTags); const newSecretTags = secsUpdatedTag.flatMap(({ tags: secretTags = [], secretId }) => secretTags.map((tag) => ({ [`${TableName.SecretTag}Id` as const]: tag, [`${TableName.Secret}Id` as const]: secretId })) ); + console.log(newSecretTags); if (newSecretTags.length) { const secTags = await secretTagDAL.saveTagsToSecret(newSecretTags, tx); const secVersionsGroupBySecId = groupBy(secretVersions, (i) => i.secretId); diff --git a/frontend/src/views/SecretMainPage/components/SecretListView/SecretItem.tsx b/frontend/src/views/SecretMainPage/components/SecretListView/SecretItem.tsx index d41d97b07..aec0573ef 100644 --- a/frontend/src/views/SecretMainPage/components/SecretListView/SecretItem.tsx +++ b/frontend/src/views/SecretMainPage/components/SecretListView/SecretItem.tsx @@ -325,7 +325,7 @@ export const SecretItem = memo( return ( handleTagSelect(tag)} - key={tagId} + key={`${secret.id}-${tagId}`} icon={isTagSelected && } iconPos="right" > @@ -339,7 +339,7 @@ export const SecretItem = memo( ); })} - +