mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
feat(infisical-pg): completed support for tags in secret snapshot
This commit is contained in:
@@ -27,7 +27,7 @@ export const getDefaultOnPremFeatures = (): TFeatureSet => ({
|
||||
status: null,
|
||||
trial_end: null,
|
||||
has_used_trial: true,
|
||||
secretApproval: true,
|
||||
secretApproval: false,
|
||||
secretRotation: true
|
||||
});
|
||||
|
||||
|
||||
@@ -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<TSecretDALFactory, "delete" | "insertMany">;
|
||||
secretTagDAL: Pick<TSecretTagDALFactory, "saveTagsToSecret">;
|
||||
secretVersionTagDAL: Pick<TSecretVersionTagDALFactory, "insertMany">;
|
||||
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<string, string[]> = {};
|
||||
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,
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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]);
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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" });
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -325,7 +325,7 @@ export const SecretItem = memo(
|
||||
return (
|
||||
<DropdownMenuItem
|
||||
onClick={() => handleTagSelect(tag)}
|
||||
key={tagId}
|
||||
key={`${secret.id}-${tagId}`}
|
||||
icon={isTagSelected && <FontAwesomeIcon icon={faCheckCircle} />}
|
||||
iconPos="right"
|
||||
>
|
||||
@@ -339,7 +339,7 @@ export const SecretItem = memo(
|
||||
</DropdownMenuItem>
|
||||
);
|
||||
})}
|
||||
<DropdownMenuItem className="px-1.5">
|
||||
<DropdownMenuItem className="px-1.5" asChild>
|
||||
<Button
|
||||
size="xs"
|
||||
className="w-full"
|
||||
|
||||
@@ -97,7 +97,6 @@ export const SnapshotView = ({
|
||||
{}
|
||||
);
|
||||
const diffView: Array<TDiffView<DecryptedSecret>> = [];
|
||||
console.log({ rollingSecrets, secrets });
|
||||
rollingSecrets.forEach((rollSecret) => {
|
||||
const { id } = rollSecret;
|
||||
const doesExist = Boolean(secretGroupById?.[id]);
|
||||
@@ -119,7 +118,7 @@ export const SnapshotView = ({
|
||||
});
|
||||
return diffView;
|
||||
}, [secrets, rollingSecrets]);
|
||||
console.log(secretDiffView);
|
||||
|
||||
const handleClickRollback = async () => {
|
||||
if (!snapshotData?.id) {
|
||||
createNotification({
|
||||
|
||||
Reference in New Issue
Block a user