mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
Merge pull request #4466 from Infisical/fix/secretImportsPermissionIssue
Fix folder path and environment on secret imports
This commit is contained in:
@@ -314,8 +314,8 @@ describe("Secret expansion", () => {
|
||||
expect(listSecrets.imports).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
secretPath: `/__reserve_replication_${secretImportFromProdToDev.id}`,
|
||||
environment: seedData1.environment.slug,
|
||||
secretPath: "/deep/nested",
|
||||
environment: "prod",
|
||||
secrets: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
secretKey: "NESTED_KEY_1",
|
||||
|
||||
@@ -59,7 +59,7 @@ type TSecretReplicationServiceFactoryDep = {
|
||||
TSecretVersionV2DALFactory,
|
||||
"find" | "insertMany" | "update" | "findLatestVersionMany"
|
||||
>;
|
||||
secretImportDAL: Pick<TSecretImportDALFactory, "find" | "updateById" | "findByFolderIds">;
|
||||
secretImportDAL: Pick<TSecretImportDALFactory, "find" | "updateById" | "findByFolderIds" | "findByIds">;
|
||||
folderDAL: Pick<
|
||||
TSecretFolderDALFactory,
|
||||
"findSecretPathByFolderIds" | "findBySecretPath" | "create" | "findOne" | "findByManySecretPath"
|
||||
|
||||
@@ -39,7 +39,7 @@ const getIntegrationSecretsV2 = async (
|
||||
},
|
||||
secretV2BridgeDAL: Pick<TSecretV2BridgeDALFactory, "find" | "findByFolderId">,
|
||||
folderDAL: Pick<TSecretFolderDALFactory, "findByManySecretPath">,
|
||||
secretImportDAL: Pick<TSecretImportDALFactory, "find" | "findByFolderIds">
|
||||
secretImportDAL: Pick<TSecretImportDALFactory, "find" | "findByFolderIds" | "findByIds">
|
||||
) => {
|
||||
const content: Record<string, boolean> = {};
|
||||
if (dto.depth > MAX_SYNC_SECRET_DEPTH) {
|
||||
@@ -300,7 +300,7 @@ export const deleteIntegrationSecrets = async ({
|
||||
projectBotService: Pick<TProjectBotServiceFactory, "getBotKey">;
|
||||
secretV2BridgeDAL: Pick<TSecretV2BridgeDALFactory, "find" | "findByFolderId">;
|
||||
folderDAL: Pick<TSecretFolderDALFactory, "findByManySecretPath" | "findBySecretPath">;
|
||||
secretImportDAL: Pick<TSecretImportDALFactory, "find" | "findByFolderIds">;
|
||||
secretImportDAL: Pick<TSecretImportDALFactory, "find" | "findByFolderIds" | "findByIds">;
|
||||
secretDAL: Pick<TSecretDALFactory, "findByFolderId">;
|
||||
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
|
||||
}) => {
|
||||
|
||||
@@ -40,7 +40,7 @@ type TIntegrationServiceFactoryDep = {
|
||||
projectBotService: TProjectBotServiceFactory;
|
||||
secretQueueService: Pick<TSecretQueueFactory, "syncIntegrations">;
|
||||
secretV2BridgeDAL: Pick<TSecretV2BridgeDALFactory, "find" | "findByFolderId">;
|
||||
secretImportDAL: Pick<TSecretImportDALFactory, "find" | "findByFolderIds">;
|
||||
secretImportDAL: Pick<TSecretImportDALFactory, "find" | "findByFolderIds" | "findByIds">;
|
||||
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
|
||||
secretDAL: Pick<TSecretDALFactory, "findByFolderId">;
|
||||
};
|
||||
|
||||
@@ -127,6 +127,27 @@ export const secretImportDALFactory = (db: TDbClient) => {
|
||||
}
|
||||
};
|
||||
|
||||
const findByIds = async (ids: string[], tx?: Knex) => {
|
||||
try {
|
||||
const docs = await (tx || db.replicaNode())(TableName.SecretImport)
|
||||
.whereIn(`${TableName.SecretImport}.id`, ids)
|
||||
.join(TableName.Environment, `${TableName.SecretImport}.importEnv`, `${TableName.Environment}.id`)
|
||||
.select(
|
||||
db.ref("*").withSchema(TableName.SecretImport) as unknown as keyof TSecretImports,
|
||||
db.ref("slug").withSchema(TableName.Environment),
|
||||
db.ref("name").withSchema(TableName.Environment),
|
||||
db.ref("id").withSchema(TableName.Environment).as("envId")
|
||||
);
|
||||
|
||||
return docs.map(({ envId, slug, name, ...el }) => ({
|
||||
...el,
|
||||
importEnv: { id: envId, slug, name }
|
||||
}));
|
||||
} catch (error) {
|
||||
throw new DatabaseError({ error, name: "Find secret imports by ids" });
|
||||
}
|
||||
};
|
||||
|
||||
const getProjectImportCount = async (
|
||||
{ search, ...filter }: Partial<TSecretImports & { projectId: string; search?: string }>,
|
||||
tx?: Knex
|
||||
@@ -325,6 +346,7 @@ export const secretImportDALFactory = (db: TDbClient) => {
|
||||
...secretImportOrm,
|
||||
find,
|
||||
findById,
|
||||
findByIds,
|
||||
findByFolderIds,
|
||||
findLastImportPosition,
|
||||
updateAllPosition,
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import RE2 from "re2";
|
||||
|
||||
import { SecretType, TSecretImports, TSecrets, TSecretsV2 } from "@app/db/schemas";
|
||||
import { groupBy, unique } from "@app/lib/fn";
|
||||
|
||||
@@ -54,6 +56,74 @@ type TSecretImportSecretsV2 = {
|
||||
|
||||
const LEVEL_BREAK = 10;
|
||||
const getImportUniqKey = (envSlug: string, path: string) => `${envSlug}=${path}`;
|
||||
const RESERVED_IMPORT_REGEX = new RE2("/__reserve_replication_([a-f0-9-]{36})");
|
||||
|
||||
/**
|
||||
* Processes reserved imports by resolving them to their replication source.
|
||||
*/
|
||||
const processReservedImports = async <
|
||||
T extends {
|
||||
isReserved?: boolean | null;
|
||||
importPath: string;
|
||||
importEnv: { id: string; slug: string; name: string };
|
||||
folderId: string;
|
||||
}
|
||||
>(
|
||||
imports: T[],
|
||||
secretImportDAL: Pick<TSecretImportDALFactory, "findByIds">
|
||||
): Promise<T[]> => {
|
||||
const reservedImportIds: string[] = [];
|
||||
|
||||
imports.forEach((secretImport) => {
|
||||
if (secretImport.isReserved) {
|
||||
const reservedMatch = RESERVED_IMPORT_REGEX.exec(secretImport.importPath);
|
||||
if (reservedMatch) {
|
||||
const referencedImportId = reservedMatch[1];
|
||||
reservedImportIds.push(referencedImportId);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (reservedImportIds.length === 0) {
|
||||
return imports;
|
||||
}
|
||||
|
||||
try {
|
||||
const importDetailsMap = new Map<
|
||||
string,
|
||||
{ importPath: string; importEnv: { id: string; slug: string; name: string } }
|
||||
>();
|
||||
|
||||
const referencedImports = await secretImportDAL.findByIds(reservedImportIds);
|
||||
referencedImports.forEach((referencedImport) => {
|
||||
importDetailsMap.set(referencedImport.id, {
|
||||
importPath: referencedImport.importPath,
|
||||
importEnv: referencedImport.importEnv
|
||||
});
|
||||
});
|
||||
|
||||
return imports.map((secretImport) => {
|
||||
if (secretImport.isReserved) {
|
||||
const reservedMatch = RESERVED_IMPORT_REGEX.exec(secretImport.importPath);
|
||||
if (reservedMatch) {
|
||||
const referencedImportId = reservedMatch[1];
|
||||
const referencedDetails = importDetailsMap.get(referencedImportId);
|
||||
|
||||
if (referencedDetails) {
|
||||
return {
|
||||
...secretImport,
|
||||
importPath: referencedDetails.importPath,
|
||||
importEnv: referencedDetails.importEnv
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
return secretImport;
|
||||
});
|
||||
} catch (error) {
|
||||
return imports;
|
||||
}
|
||||
};
|
||||
export const fnSecretsFromImports = async ({
|
||||
allowedImports: possibleCyclicImports,
|
||||
folderDAL,
|
||||
@@ -167,7 +237,7 @@ export const fnSecretsV2FromImports = async ({
|
||||
folderDAL: Pick<TSecretFolderDALFactory, "findByManySecretPath">;
|
||||
viewSecretValue: boolean;
|
||||
secretDAL: Pick<TSecretV2BridgeDALFactory, "find">;
|
||||
secretImportDAL: Pick<TSecretImportDALFactory, "findByFolderIds">;
|
||||
secretImportDAL: Pick<TSecretImportDALFactory, "findByFolderIds" | "findByIds">;
|
||||
decryptor: (value?: Buffer | null) => string;
|
||||
expandSecretReferences?: (inputSecret: {
|
||||
value?: string;
|
||||
@@ -188,6 +258,10 @@ export const fnSecretsV2FromImports = async ({
|
||||
})[];
|
||||
}[] = [{ secretImports: rootSecretImports, depth: 0, parentImportedSecrets: [] }];
|
||||
|
||||
const processedSecretImports = await processReservedImports(rootSecretImports, secretImportDAL);
|
||||
|
||||
stack[0] = { secretImports: processedSecretImports, depth: 0, parentImportedSecrets: [] };
|
||||
|
||||
const processedImports: TSecretImportSecretsV2[] = [];
|
||||
|
||||
while (stack.length) {
|
||||
|
||||
@@ -80,7 +80,7 @@ type TSecretSyncQueueFactoryDep = {
|
||||
| "deleteMany"
|
||||
| "invalidateSecretCacheByProjectId"
|
||||
>;
|
||||
secretImportDAL: Pick<TSecretImportDALFactory, "find" | "findByFolderIds">;
|
||||
secretImportDAL: Pick<TSecretImportDALFactory, "find" | "findByFolderIds" | "findByIds">;
|
||||
secretSyncDAL: Pick<TSecretSyncDALFactory, "findById" | "find" | "updateById" | "deleteById" | "update">;
|
||||
auditLogService: Pick<TAuditLogServiceFactory, "createAuditLog">;
|
||||
projectMembershipDAL: Pick<TProjectMembershipDALFactory, "findAllProjectMembers">;
|
||||
|
||||
@@ -108,7 +108,7 @@ type TSecretV2BridgeServiceFactoryDep = {
|
||||
| "findBySecretPathMultiEnv"
|
||||
| "findSecretPathByFolderIds"
|
||||
>;
|
||||
secretImportDAL: Pick<TSecretImportDALFactory, "find" | "findByFolderIds">;
|
||||
secretImportDAL: Pick<TSecretImportDALFactory, "find" | "findByFolderIds" | "findByIds">;
|
||||
secretQueueService: Pick<TSecretQueueFactory, "syncSecrets" | "handleSecretReminder" | "removeSecretReminder">;
|
||||
secretApprovalPolicyService: Pick<TSecretApprovalPolicyServiceFactory, "getSecretApprovalPolicy">;
|
||||
secretApprovalRequestDAL: Pick<TSecretApprovalRequestDALFactory, "create" | "transaction">;
|
||||
|
||||
@@ -86,7 +86,7 @@ type TSecretQueueFactoryDep = {
|
||||
integrationAuthService: Pick<TIntegrationAuthServiceFactory, "getIntegrationAccessToken">;
|
||||
folderDAL: TSecretFolderDALFactory;
|
||||
secretDAL: TSecretDALFactory;
|
||||
secretImportDAL: Pick<TSecretImportDALFactory, "find" | "findByFolderIds">;
|
||||
secretImportDAL: Pick<TSecretImportDALFactory, "find" | "findByFolderIds" | "findByIds">;
|
||||
webhookDAL: Pick<TWebhookDALFactory, "findAllWebhooks" | "transaction" | "update" | "bulkUpdate">;
|
||||
projectEnvDAL: Pick<TProjectEnvDALFactory, "findOne" | "find">;
|
||||
projectDAL: TProjectDALFactory;
|
||||
|
||||
Reference in New Issue
Block a user