Compare commits

..

1 Commits

Author SHA1 Message Date
x032205
c67194f5a2 Checkpoint 2025-07-29 15:24:03 -04:00
600 changed files with 7639 additions and 14381 deletions

View File

@@ -338,6 +338,9 @@ import {
TSecretImports,
TSecretImportsInsert,
TSecretImportsUpdate,
TSecretImportVersions,
TSecretImportVersionsInsert,
TSecretImportVersionsUpdate,
TSecretReferences,
TSecretReferencesInsert,
TSecretReferencesUpdate,
@@ -754,6 +757,11 @@ declare module "knex/types/tables" {
TSecretImportsInsert,
TSecretImportsUpdate
>;
[TableName.SecretImportVersion]: KnexOriginal.CompositeTableType<
TSecretImportVersions,
TSecretImportVersionsInsert,
TSecretImportVersionsUpdate
>;
[TableName.Integration]: KnexOriginal.CompositeTableType<TIntegrations, TIntegrationsInsert, TIntegrationsUpdate>;
[TableName.Webhook]: KnexOriginal.CompositeTableType<TWebhooks, TWebhooksInsert, TWebhooksUpdate>;
[TableName.ServiceToken]: KnexOriginal.CompositeTableType<

View File

@@ -1,432 +0,0 @@
import slugify from "@sindresorhus/slugify";
import { Knex } from "knex";
import { v4 as uuidV4 } from "uuid";
import { alphaNumericNanoId } from "@app/lib/nanoid";
import { ProjectType, TableName } from "../schemas";
/* eslint-disable no-await-in-loop,@typescript-eslint/ban-ts-comment */
// Single query to get all projects that need any kind of kickout
const getProjectsNeedingKickouts = async (
knex: Knex
): Promise<
Array<{
id: string;
defaultProduct: string;
needsSecretManager: boolean;
needsCertManager: boolean;
needsSecretScanning: boolean;
needsKms: boolean;
needsSsh: boolean;
}>
> => {
const result = await knex.raw(
`
SELECT DISTINCT
p.id,
p."defaultProduct",
-- Use CASE with direct joins instead of EXISTS subqueries
CASE WHEN p."defaultProduct" != 'secret-manager' AND s.secret_exists IS NOT NULL THEN true ELSE false END AS "needsSecretManager",
CASE WHEN p."defaultProduct" != 'cert-manager' AND ca.ca_exists IS NOT NULL THEN true ELSE false END AS "needsCertManager",
CASE WHEN p."defaultProduct" != 'secret-scanning' AND ssds.ssds_exists IS NOT NULL THEN true ELSE false END AS "needsSecretScanning",
CASE WHEN p."defaultProduct" != 'kms' AND kk.kms_exists IS NOT NULL THEN true ELSE false END AS "needsKms",
CASE WHEN p."defaultProduct" != 'ssh' AND sc.ssh_exists IS NOT NULL THEN true ELSE false END AS "needsSsh"
FROM projects p
LEFT JOIN (
SELECT DISTINCT e."projectId", 1 as secret_exists
FROM secrets_v2 s
JOIN secret_folders sf ON sf.id = s."folderId"
JOIN project_environments e ON e.id = sf."envId"
) s ON s."projectId" = p.id AND p."defaultProduct" != 'secret-manager'
LEFT JOIN (
SELECT DISTINCT "projectId", 1 as ca_exists
FROM certificate_authorities
) ca ON ca."projectId" = p.id AND p."defaultProduct" != 'cert-manager'
LEFT JOIN (
SELECT DISTINCT "projectId", 1 as ssds_exists
FROM secret_scanning_data_sources
) ssds ON ssds."projectId" = p.id AND p."defaultProduct" != 'secret-scanning'
LEFT JOIN (
SELECT DISTINCT "projectId", 1 as kms_exists
FROM kms_keys
WHERE "isReserved" = false
) kk ON kk."projectId" = p.id AND p."defaultProduct" != 'kms'
LEFT JOIN (
SELECT DISTINCT sca."projectId", 1 as ssh_exists
FROM ssh_certificates sc
JOIN ssh_certificate_authorities sca ON sca.id = sc."sshCaId"
) sc ON sc."projectId" = p.id AND p."defaultProduct" != 'ssh'
WHERE p."defaultProduct" IS NOT NULL
AND (
(p."defaultProduct" != 'secret-manager' AND s.secret_exists IS NOT NULL) OR
(p."defaultProduct" != 'cert-manager' AND ca.ca_exists IS NOT NULL) OR
(p."defaultProduct" != 'secret-scanning' AND ssds.ssds_exists IS NOT NULL) OR
(p."defaultProduct" != 'kms' AND kk.kms_exists IS NOT NULL) OR
(p."defaultProduct" != 'ssh' AND sc.ssh_exists IS NOT NULL)
)
`
);
return result.rows;
};
const newProject = async (knex: Knex, projectId: string, projectType: ProjectType) => {
const newProjectId = uuidV4();
const project = await knex(TableName.Project).where("id", projectId).first();
await knex(TableName.Project).insert({
...project,
type: projectType,
defaultProduct: null,
// @ts-ignore id is required
id: newProjectId,
slug: slugify(`${project?.name}-${alphaNumericNanoId(8)}`)
});
const customRoleMapping: Record<string, string> = {};
const projectCustomRoles = await knex(TableName.ProjectRoles).where("projectId", projectId);
if (projectCustomRoles.length) {
await knex.batchInsert(
TableName.ProjectRoles,
projectCustomRoles.map((el) => {
const id = uuidV4();
customRoleMapping[el.id] = id;
return {
...el,
id,
projectId: newProjectId,
permissions: el.permissions ? JSON.stringify(el.permissions) : el.permissions
};
})
);
}
const groupMembershipMapping: Record<string, string> = {};
const groupMemberships = await knex(TableName.GroupProjectMembership).where("projectId", projectId);
if (groupMemberships.length) {
await knex.batchInsert(
TableName.GroupProjectMembership,
groupMemberships.map((el) => {
const id = uuidV4();
groupMembershipMapping[el.id] = id;
return { ...el, id, projectId: newProjectId };
})
);
}
const groupMembershipRoles = await knex(TableName.GroupProjectMembershipRole).whereIn(
"projectMembershipId",
groupMemberships.map((el) => el.id)
);
if (groupMembershipRoles.length) {
await knex.batchInsert(
TableName.GroupProjectMembershipRole,
groupMembershipRoles.map((el) => {
const id = uuidV4();
const projectMembershipId = groupMembershipMapping[el.projectMembershipId];
const customRoleId = el.customRoleId ? customRoleMapping[el.customRoleId] : el.customRoleId;
return { ...el, id, projectMembershipId, customRoleId };
})
);
}
const identityProjectMembershipMapping: Record<string, string> = {};
const identities = await knex(TableName.IdentityProjectMembership).where("projectId", projectId);
if (identities.length) {
await knex.batchInsert(
TableName.IdentityProjectMembership,
identities.map((el) => {
const id = uuidV4();
identityProjectMembershipMapping[el.id] = id;
return { ...el, id, projectId: newProjectId };
})
);
}
const identitiesRoles = await knex(TableName.IdentityProjectMembershipRole).whereIn(
"projectMembershipId",
identities.map((el) => el.id)
);
if (identitiesRoles.length) {
await knex.batchInsert(
TableName.IdentityProjectMembershipRole,
identitiesRoles.map((el) => {
const id = uuidV4();
const projectMembershipId = identityProjectMembershipMapping[el.projectMembershipId];
const customRoleId = el.customRoleId ? customRoleMapping[el.customRoleId] : el.customRoleId;
return { ...el, id, projectMembershipId, customRoleId };
})
);
}
const projectMembershipMapping: Record<string, string> = {};
const projectUserMembers = await knex(TableName.ProjectMembership).where("projectId", projectId);
if (projectUserMembers.length) {
await knex.batchInsert(
TableName.ProjectMembership,
projectUserMembers.map((el) => {
const id = uuidV4();
projectMembershipMapping[el.id] = id;
return { ...el, id, projectId: newProjectId };
})
);
}
const membershipRoles = await knex(TableName.ProjectUserMembershipRole).whereIn(
"projectMembershipId",
projectUserMembers.map((el) => el.id)
);
if (membershipRoles.length) {
await knex.batchInsert(
TableName.ProjectUserMembershipRole,
membershipRoles.map((el) => {
const id = uuidV4();
const projectMembershipId = projectMembershipMapping[el.projectMembershipId];
const customRoleId = el.customRoleId ? customRoleMapping[el.customRoleId] : el.customRoleId;
return { ...el, id, projectMembershipId, customRoleId };
})
);
}
const kmsKeys = await knex(TableName.KmsKey).where("projectId", projectId).andWhere("isReserved", true);
if (kmsKeys.length) {
await knex.batchInsert(
TableName.KmsKey,
kmsKeys.map((el) => {
const id = uuidV4();
const slug = slugify(alphaNumericNanoId(8).toLowerCase());
return { ...el, id, slug, projectId: newProjectId };
})
);
}
const projectBot = await knex(TableName.ProjectBot).where("projectId", projectId).first();
if (projectBot) {
const newProjectBot = { ...projectBot, id: uuidV4(), projectId: newProjectId };
await knex(TableName.ProjectBot).insert(newProjectBot);
}
const projectKeys = await knex(TableName.ProjectKeys).where("projectId", projectId);
if (projectKeys.length) {
await knex.batchInsert(
TableName.ProjectKeys,
projectKeys.map((el) => {
const id = uuidV4();
return { ...el, id, projectId: newProjectId };
})
);
}
const projectGateways = await knex(TableName.ProjectGateway).where("projectId", projectId);
if (projectGateways.length) {
await knex.batchInsert(
TableName.ProjectGateway,
projectGateways.map((el) => {
const id = uuidV4();
return { ...el, id, projectId: newProjectId };
})
);
}
const projectSlackConfigs = await knex(TableName.ProjectSlackConfigs).where("projectId", projectId);
if (projectSlackConfigs.length) {
await knex.batchInsert(
TableName.ProjectSlackConfigs,
projectSlackConfigs.map((el) => {
const id = uuidV4();
return { ...el, id, projectId: newProjectId };
})
);
}
const projectMicrosoftTeamsConfigs = await knex(TableName.ProjectMicrosoftTeamsConfigs).where("projectId", projectId);
if (projectMicrosoftTeamsConfigs.length) {
await knex.batchInsert(
TableName.ProjectMicrosoftTeamsConfigs,
projectMicrosoftTeamsConfigs.map((el) => {
const id = uuidV4();
return { ...el, id, projectId: newProjectId };
})
);
}
const trustedIps = await knex(TableName.TrustedIps).where("projectId", projectId);
if (trustedIps.length) {
await knex.batchInsert(
TableName.TrustedIps,
trustedIps.map((el) => {
const id = uuidV4();
return { ...el, id, projectId: newProjectId };
})
);
}
return newProjectId;
};
const kickOutSecretManagerProject = async (knex: Knex, oldProjectId: string) => {
const newProjectId = await newProject(knex, oldProjectId, ProjectType.SecretManager);
await knex(TableName.IntegrationAuth).where("projectId", oldProjectId).update("projectId", newProjectId);
await knex(TableName.Environment).where("projectId", oldProjectId).update("projectId", newProjectId);
await knex(TableName.SecretBlindIndex).where("projectId", oldProjectId).update("projectId", newProjectId);
await knex(TableName.SecretSync).where("projectId", oldProjectId).update("projectId", newProjectId);
await knex(TableName.SecretTag).where("projectId", oldProjectId).update("projectId", newProjectId);
await knex(TableName.SecretReminderRecipients).where("projectId", oldProjectId).update("projectId", newProjectId);
await knex(TableName.ServiceToken).where("projectId", oldProjectId).update("projectId", newProjectId);
};
const kickOutCertManagerProject = async (knex: Knex, oldProjectId: string) => {
const newProjectId = await newProject(knex, oldProjectId, ProjectType.CertificateManager);
await knex(TableName.CertificateAuthority).where("projectId", oldProjectId).update("projectId", newProjectId);
await knex(TableName.Certificate).where("projectId", oldProjectId).update("projectId", newProjectId);
await knex(TableName.PkiSubscriber).where("projectId", oldProjectId).update("projectId", newProjectId);
await knex(TableName.PkiCollection).where("projectId", oldProjectId).update("projectId", newProjectId);
await knex(TableName.PkiAlert).where("projectId", oldProjectId).update("projectId", newProjectId);
};
const kickOutSecretScanningProject = async (knex: Knex, oldProjectId: string) => {
const newProjectId = await newProject(knex, oldProjectId, ProjectType.SecretScanning);
await knex(TableName.SecretScanningConfig).where("projectId", oldProjectId).update("projectId", newProjectId);
await knex(TableName.SecretScanningDataSource).where("projectId", oldProjectId).update("projectId", newProjectId);
await knex(TableName.SecretScanningFinding).where("projectId", oldProjectId).update("projectId", newProjectId);
};
const kickOutKmsProject = async (knex: Knex, oldProjectId: string) => {
const newProjectId = await newProject(knex, oldProjectId, ProjectType.KMS);
await knex(TableName.KmsKey)
.where("projectId", oldProjectId)
.andWhere("isReserved", false)
.update("projectId", newProjectId);
await knex(TableName.KmipClient).where("projectId", oldProjectId).update("projectId", newProjectId);
};
const kickOutSshProject = async (knex: Knex, oldProjectId: string) => {
const newProjectId = await newProject(knex, oldProjectId, ProjectType.SSH);
await knex(TableName.SshHost).where("projectId", oldProjectId).update("projectId", newProjectId);
await knex(TableName.ProjectSshConfig).where("projectId", oldProjectId).update("projectId", newProjectId);
await knex(TableName.SshCertificateAuthority).where("projectId", oldProjectId).update("projectId", newProjectId);
await knex(TableName.SshHostGroup).where("projectId", oldProjectId).update("projectId", newProjectId);
};
const BATCH_SIZE = 1000;
const MIGRATION_TIMEOUT = 30 * 60 * 1000; // 30 minutes
export async function up(knex: Knex): Promise<void> {
const result = await knex.raw("SHOW statement_timeout");
const originalTimeout = result.rows[0].statement_timeout;
try {
await knex.raw(`SET statement_timeout = ${MIGRATION_TIMEOUT}`);
const hasTemplateTypeColumn = await knex.schema.hasColumn(TableName.ProjectTemplates, "type");
if (hasTemplateTypeColumn) {
await knex(TableName.ProjectTemplates).whereNull("type").update({
type: ProjectType.SecretManager
});
await knex.schema.alterTable(TableName.ProjectTemplates, (t) => {
t.string("type").notNullable().defaultTo(ProjectType.SecretManager).alter();
});
}
const hasTypeColumn = await knex.schema.hasColumn(TableName.Project, "type");
const hasDefaultTypeColumn = await knex.schema.hasColumn(TableName.Project, "defaultProduct");
if (hasTypeColumn && hasDefaultTypeColumn) {
await knex(TableName.Project).update({
// eslint-disable-next-line
// @ts-ignore this is because this field is created later
type: knex.raw(`"defaultProduct"`)
});
await knex.schema.alterTable(TableName.Project, (t) => {
t.string("type").notNullable().alter();
t.string("defaultProduct").nullable().alter();
});
// Get all projects that need kickouts in a single query
const projectsNeedingKickouts = await getProjectsNeedingKickouts(knex);
// Process projects in batches to avoid overwhelming the database
for (let i = 0; i < projectsNeedingKickouts.length; i += projectsNeedingKickouts.length) {
const batch = projectsNeedingKickouts.slice(i, i + BATCH_SIZE);
const processedIds: string[] = [];
for (const project of batch) {
const kickoutPromises: Promise<void>[] = [];
// Only add kickouts that are actually needed (flags are pre-computed)
if (project.needsSecretManager) {
kickoutPromises.push(kickOutSecretManagerProject(knex, project.id));
}
if (project.needsCertManager) {
kickoutPromises.push(kickOutCertManagerProject(knex, project.id));
}
if (project.needsKms) {
kickoutPromises.push(kickOutKmsProject(knex, project.id));
}
if (project.needsSsh) {
kickoutPromises.push(kickOutSshProject(knex, project.id));
}
if (project.needsSecretScanning) {
kickoutPromises.push(kickOutSecretScanningProject(knex, project.id));
}
// Execute all kickouts in parallel and handle any failures gracefully
if (kickoutPromises.length > 0) {
const results = await Promise.allSettled(kickoutPromises);
// Log any failures for debugging
results.forEach((res) => {
if (res.status === "rejected") {
throw new Error(`Migration failed for project ${project.id}: ${res.reason}`);
}
});
}
processedIds.push(project.id);
}
// Clear defaultProduct for the processed batch
if (processedIds.length > 0) {
await knex(TableName.Project).whereIn("id", processedIds).update("defaultProduct", null);
}
}
}
} finally {
await knex.raw(`SET statement_timeout = '${originalTimeout}'`);
}
}
export async function down(knex: Knex): Promise<void> {
const hasTypeColumn = await knex.schema.hasColumn(TableName.Project, "type");
const hasDefaultTypeColumn = await knex.schema.hasColumn(TableName.Project, "defaultProduct");
if (hasTypeColumn && hasDefaultTypeColumn) {
await knex(TableName.Project).update({
// eslint-disable-next-line
// @ts-ignore this is because this field is created later
defaultProduct: knex.raw(`
CASE
WHEN "type" IS NULL OR "type" = '' THEN 'secret-manager'
ELSE "type"
END
`)
});
await knex.schema.alterTable(TableName.Project, (t) => {
t.string("type").nullable().alter();
t.string("defaultProduct").notNullable().alter();
});
}
const hasTemplateTypeColumn = await knex.schema.hasColumn(TableName.ProjectTemplates, "type");
if (hasTemplateTypeColumn) {
await knex.schema.alterTable(TableName.ProjectTemplates, (t) => {
t.string("type").nullable().alter();
});
}
}

View File

@@ -0,0 +1,61 @@
import { Knex } from "knex";
import { TableName } from "../schemas";
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
export async function up(knex: Knex): Promise<void> {
if (!(await knex.schema.hasTable(TableName.SecretImportVersion))) {
await knex.schema.createTable(TableName.SecretImportVersion, (t) => {
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
t.integer("version");
t.string("importPath").notNullable();
t.integer("position").notNullable();
t.boolean("isReplication");
t.boolean("isReserved");
t.uuid("importEnv").notNullable();
t.uuid("importId").notNullable();
t.timestamps(true, true, true);
});
await createOnUpdateTrigger(knex, TableName.SecretImportVersion);
await knex.schema.alterTable(TableName.FolderCommitChanges, (t) => {
t.uuid("importVersionId");
t.foreign("importVersionId").references("id").inTable(TableName.SecretImportVersion).onDelete("CASCADE");
t.uuid("reservedFolderCommitId");
t.foreign("reservedFolderCommitId").references("id").inTable(TableName.FolderCommit).onDelete("CASCADE");
t.index("importVersionId");
t.index("reservedFolderCommitId");
});
await knex.schema.alterTable(TableName.FolderCheckpointResources, (t) => {
t.uuid("importVersionId");
t.foreign("importVersionId").references("id").inTable(TableName.SecretImportVersion).onDelete("CASCADE");
t.uuid("reservedFolderCommitId");
t.foreign("reservedFolderCommitId").references("id").inTable(TableName.FolderCommit).onDelete("CASCADE");
});
}
}
export async function down(knex: Knex): Promise<void> {
if (await knex.schema.hasTable(TableName.SecretImportVersion)) {
await knex.schema.alterTable(TableName.FolderCommitChanges, (t) => {
t.dropColumn("importVersionId");
t.dropColumn("reservedFolderCommitId");
});
await knex.schema.alterTable(TableName.FolderCheckpointResources, (t) => {
t.dropColumn("importVersionId");
t.dropColumn("reservedFolderCommitId");
});
await knex.schema.dropTable(TableName.SecretImportVersion);
await dropOnUpdateTrigger(knex, TableName.SecretImportVersion);
}
}

View File

@@ -17,9 +17,12 @@ import { kmsRootConfigDALFactory } from "@app/services/kms/kms-root-config-dal";
import { kmsServiceFactory } from "@app/services/kms/kms-service";
import { orgDALFactory } from "@app/services/org/org-dal";
import { projectDALFactory } from "@app/services/project/project-dal";
import { projectEnvDALFactory } from "@app/services/project-env/project-env-dal";
import { resourceMetadataDALFactory } from "@app/services/resource-metadata/resource-metadata-dal";
import { secretFolderDALFactory } from "@app/services/secret-folder/secret-folder-dal";
import { secretFolderVersionDALFactory } from "@app/services/secret-folder/secret-folder-version-dal";
import { secretImportDALFactory } from "@app/services/secret-import/secret-import-dal";
import { secretImportVersionDALFactory } from "@app/services/secret-import/secret-import-version-dal";
import { secretTagDALFactory } from "@app/services/secret-tag/secret-tag-dal";
import { secretV2BridgeDALFactory } from "@app/services/secret-v2-bridge/secret-v2-bridge-dal";
import { secretVersionV2BridgeDALFactory } from "@app/services/secret-v2-bridge/secret-version-dal";
@@ -83,7 +86,10 @@ export const getMigrationPITServices = async ({
const userDAL = userDALFactory(db);
const identityDAL = identityDALFactory(db);
const folderDAL = secretFolderDALFactory(db);
const envDAL = projectEnvDALFactory(db);
const secretImportDAL = secretImportDALFactory(db);
const folderVersionDAL = secretFolderVersionDALFactory(db);
const importVersionDAL = secretImportVersionDALFactory(db);
const secretVersionV2BridgeDAL = secretVersionV2BridgeDALFactory(db);
const folderCheckpointResourcesDAL = folderCheckpointResourcesDALFactory(db);
const secretV2BridgeDAL = secretV2BridgeDALFactory({ db, keyStore });
@@ -126,7 +132,10 @@ export const getMigrationPITServices = async ({
userDAL,
identityDAL,
folderDAL,
envDAL,
secretImportDAL,
folderVersionDAL,
importVersionDAL,
secretVersionV2BridgeDAL,
projectDAL,
folderCheckpointResourcesDAL,

View File

@@ -13,7 +13,9 @@ export const FolderCheckpointResourcesSchema = z.object({
secretVersionId: z.string().uuid().nullable().optional(),
folderVersionId: z.string().uuid().nullable().optional(),
createdAt: z.date(),
updatedAt: z.date()
updatedAt: z.date(),
importVersionId: z.string().uuid().nullable().optional(),
reservedFolderCommitId: z.string().uuid().nullable().optional()
});
export type TFolderCheckpointResources = z.infer<typeof FolderCheckpointResourcesSchema>;

View File

@@ -15,7 +15,9 @@ export const FolderCommitChangesSchema = z.object({
secretVersionId: z.string().uuid().nullable().optional(),
folderVersionId: z.string().uuid().nullable().optional(),
createdAt: z.date(),
updatedAt: z.date()
updatedAt: z.date(),
importVersionId: z.string().uuid().nullable().optional(),
reservedFolderCommitId: z.string().uuid().nullable().optional()
});
export type TFolderCommitChanges = z.infer<typeof FolderCommitChangesSchema>;

View File

@@ -111,6 +111,7 @@ export * from "./secret-approval-requests-secrets-v2";
export * from "./secret-blind-indexes";
export * from "./secret-folder-versions";
export * from "./secret-folders";
export * from "./secret-import-versions";
export * from "./secret-imports";
export * from "./secret-references";
export * from "./secret-references-v2";

View File

@@ -63,6 +63,7 @@ export enum TableName {
SecretVersion = "secret_versions",
SecretFolder = "secret_folders",
SecretFolderVersion = "secret_folder_versions",
SecretImportVersion = "secret_import_versions",
SecretImport = "secret_imports",
Snapshot = "secret_snapshots",
SnapshotSecret = "secret_snapshot_secrets",
@@ -267,16 +268,6 @@ export enum ProjectType {
SecretScanning = "secret-scanning"
}
export enum ActionProjectType {
SecretManager = ProjectType.SecretManager,
CertificateManager = ProjectType.CertificateManager,
KMS = ProjectType.KMS,
SSH = ProjectType.SSH,
SecretScanning = ProjectType.SecretScanning,
// project operations that happen on all types
Any = "any"
}
export enum SortDirection {
ASC = "asc",
DESC = "desc"

View File

@@ -16,7 +16,7 @@ export const ProjectTemplatesSchema = z.object({
orgId: z.string().uuid(),
createdAt: z.date(),
updatedAt: z.date(),
type: z.string().default("secret-manager")
type: z.string().nullable().optional()
});
export type TProjectTemplates = z.infer<typeof ProjectTemplatesSchema>;

View File

@@ -25,12 +25,12 @@ export const ProjectsSchema = z.object({
kmsSecretManagerKeyId: z.string().uuid().nullable().optional(),
kmsSecretManagerEncryptedDataKey: zodBuffer.nullable().optional(),
description: z.string().nullable().optional(),
type: z.string(),
type: z.string().nullable().optional(),
enforceCapitalization: z.boolean().default(false),
hasDeleteProtection: z.boolean().default(false).nullable().optional(),
secretSharing: z.boolean().default(true),
showSnapshotsLegacy: z.boolean().default(false),
defaultProduct: z.string().nullable().optional()
defaultProduct: z.string().default("secret-manager")
});
export type TProjects = z.infer<typeof ProjectsSchema>;

View File

@@ -0,0 +1,25 @@
// Code generated by automation script, DO NOT EDIT.
// Automated by pulling database and generating zod schema
// To update. Just run npm run generate:schema
// Written by akhilmhdh.
import { z } from "zod";
import { TImmutableDBKeys } from "./models";
export const SecretImportVersionsSchema = z.object({
id: z.string().uuid(),
version: z.number().nullable().optional(),
importPath: z.string(),
position: z.number(),
isReplication: z.boolean().nullable().optional(),
isReserved: z.boolean().nullable().optional(),
importEnv: z.string().uuid(),
importId: z.string().uuid(),
createdAt: z.date(),
updatedAt: z.date()
});
export type TSecretImportVersions = z.infer<typeof SecretImportVersionsSchema>;
export type TSecretImportVersionsInsert = Omit<z.input<typeof SecretImportVersionsSchema>, TImmutableDBKeys>;
export type TSecretImportVersionsUpdate = Partial<Omit<z.input<typeof SecretImportVersionsSchema>, TImmutableDBKeys>>;

View File

@@ -3,14 +3,11 @@ import { z } from "zod";
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
import { removeTrailingSlash } from "@app/lib/fn";
import { isValidFolderName } from "@app/lib/validator";
import { readLimit, secretsLimit } from "@app/server/config/rateLimiter";
import { SecretNameSchema } from "@app/server/lib/schemas";
import { readLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { booleanSchema } from "@app/server/routes/sanitizedSchemas";
import { AuthMode } from "@app/services/auth/auth-type";
import { commitChangesResponseSchema, resourceChangeSchema } from "@app/services/folder-commit/folder-commit-schemas";
import { ResourceMetadataSchema } from "@app/services/resource-metadata/resource-metadata-schema";
const commitHistoryItemSchema = z.object({
id: z.string(),
@@ -416,166 +413,4 @@ export const registerPITRouter = async (server: FastifyZodProvider) => {
return result;
}
});
server.route({
method: "POST",
url: "/batch/commit",
config: {
rateLimit: secretsLimit
},
schema: {
hide: true,
description: "Commit changes",
security: [
{
bearerAuth: []
}
],
body: z.object({
projectId: z.string().trim(),
environment: z.string().trim(),
secretPath: z.string().trim().default("/").transform(removeTrailingSlash),
message: z
.string()
.trim()
.min(1)
.max(255)
.refine((message) => message.trim() !== "", {
message: "Commit message cannot be empty"
}),
changes: z.object({
secrets: z.object({
create: z
.array(
z.object({
secretKey: SecretNameSchema,
secretValue: z.string().transform((val) => (val.at(-1) === "\n" ? `${val.trim()}\n` : val.trim())),
secretComment: z.string().trim().optional().default(""),
skipMultilineEncoding: z.boolean().optional(),
metadata: z.record(z.string()).optional(),
secretMetadata: ResourceMetadataSchema.optional(),
tagIds: z.string().array().optional()
})
)
.optional(),
update: z
.array(
z.object({
secretKey: SecretNameSchema,
newSecretName: SecretNameSchema.optional(),
secretValue: z
.string()
.transform((val) => (val.at(-1) === "\n" ? `${val.trim()}\n` : val.trim()))
.optional(),
secretComment: z.string().trim().optional().default(""),
skipMultilineEncoding: z.boolean().optional(),
metadata: z.record(z.string()).optional(),
secretMetadata: ResourceMetadataSchema.optional(),
tagIds: z.string().array().optional()
})
)
.optional(),
delete: z
.array(
z.object({
secretKey: SecretNameSchema
})
)
.optional()
}),
folders: z.object({
create: z
.array(
z.object({
folderName: z
.string()
.trim()
.refine((name) => isValidFolderName(name), {
message: "Invalid folder name. Only alphanumeric characters, dashes, and underscores are allowed."
}),
description: z.string().optional()
})
)
.optional(),
update: z
.array(
z.object({
folderName: z
.string()
.trim()
.refine((name) => isValidFolderName(name), {
message: "Invalid folder name. Only alphanumeric characters, dashes, and underscores are allowed."
}),
description: z.string().nullable().optional(),
id: z.string()
})
)
.optional(),
delete: z
.array(
z.object({
folderName: z
.string()
.trim()
.refine((name) => isValidFolderName(name), {
message: "Invalid folder name. Only alphanumeric characters, dashes, and underscores are allowed."
}),
id: z.string()
})
)
.optional()
})
})
}),
response: {
200: z.object({
message: z.string()
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const result = await server.services.pit.processNewCommitRaw({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
actorAuthMethod: req.permission.authMethod,
projectId: req.body.projectId,
environment: req.body.environment,
secretPath: req.body.secretPath,
message: req.body.message,
changes: {
secrets: req.body.changes.secrets,
folders: req.body.changes.folders
}
});
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
projectId: req.body.projectId,
event: {
type: EventType.PIT_PROCESS_NEW_COMMIT_RAW,
metadata: {
commitId: result.commitId,
approvalId: result.approvalId,
projectId: req.body.projectId,
environment: req.body.environment,
secretPath: req.body.secretPath,
message: req.body.message
}
}
});
for await (const event of result.secretMutationEvents) {
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
orgId: req.permission.orgId,
projectId: req.body.projectId,
event
});
}
return { message: "success" };
}
});
};

View File

@@ -1,6 +1,6 @@
import { z } from "zod";
import { ProjectMembershipRole, ProjectTemplatesSchema, ProjectType } from "@app/db/schemas";
import { ProjectMembershipRole, ProjectTemplatesSchema } from "@app/db/schemas";
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
import { ProjectPermissionV2Schema } from "@app/ee/services/permission/project-permission";
import { isInfisicalProjectTemplate } from "@app/ee/services/project-template/project-template-fns";
@@ -104,9 +104,6 @@ export const registerProjectTemplateRouter = async (server: FastifyZodProvider)
hide: false,
tags: [ApiDocsTags.ProjectTemplates],
description: "List project templates for the current organization.",
querystring: z.object({
type: z.nativeEnum(ProjectType).optional().describe(ProjectTemplates.LIST.type)
}),
response: {
200: z.object({
projectTemplates: SanitizedProjectTemplateSchema.array()
@@ -115,10 +112,7 @@ export const registerProjectTemplateRouter = async (server: FastifyZodProvider)
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const projectTemplates = await server.services.projectTemplate.listProjectTemplatesByOrg(
req.permission,
req.query.type
);
const projectTemplates = await server.services.projectTemplate.listProjectTemplatesByOrg(req.permission);
const auditTemplates = projectTemplates.filter((template) => !isInfisicalProjectTemplate(template.name));
@@ -197,7 +191,6 @@ export const registerProjectTemplateRouter = async (server: FastifyZodProvider)
.describe(ProjectTemplates.CREATE.name),
description: z.string().max(256).trim().optional().describe(ProjectTemplates.CREATE.description),
roles: ProjectTemplateRolesSchema.default([]).describe(ProjectTemplates.CREATE.roles),
type: z.nativeEnum(ProjectType).describe(ProjectTemplates.CREATE.type),
environments: ProjectTemplateEnvironmentsSchema.describe(ProjectTemplates.CREATE.environments).optional()
}),
response: {

View File

@@ -315,12 +315,10 @@ export const registerSecretRotationEndpoints = <
querystring: z.object({
deleteSecrets: z
.enum(["true", "false"])
.optional()
.transform((value) => value === "true")
.describe(SecretRotations.DELETE(type).deleteSecrets),
revokeGeneratedCredentials: z
.enum(["true", "false"])
.optional()
.transform((value) => value === "true")
.describe(SecretRotations.DELETE(type).revokeGeneratedCredentials)
}),

View File

@@ -1,6 +1,5 @@
import { ForbiddenError } from "@casl/ability";
import { ActionProjectType } from "@app/db/schemas";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
@@ -117,8 +116,7 @@ export const accessApprovalPolicyServiceFactory = ({
actorId,
projectId: project.id,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -274,8 +272,7 @@ export const accessApprovalPolicyServiceFactory = ({
actorId,
projectId: project.id,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
const accessApprovalPolicies = await accessApprovalPolicyDAL.find({ projectId: project.id, deletedAt: null });
@@ -340,8 +337,7 @@ export const accessApprovalPolicyServiceFactory = ({
actorId,
projectId: accessApprovalPolicy.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.SecretApproval);
@@ -537,8 +533,7 @@ export const accessApprovalPolicyServiceFactory = ({
actorId,
projectId: policy.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Delete,
@@ -588,8 +583,7 @@ export const accessApprovalPolicyServiceFactory = ({
actorId,
projectId: project.id,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
if (!membership) {
throw new ForbiddenRequestError({ message: "You are not a member of this project" });
@@ -628,8 +622,7 @@ export const accessApprovalPolicyServiceFactory = ({
actorId,
projectId: policy.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretApproval);

View File

@@ -1,7 +1,7 @@
import slugify from "@sindresorhus/slugify";
import msFn from "ms";
import { ActionProjectType, ProjectMembershipRole } from "@app/db/schemas";
import { ProjectMembershipRole } from "@app/db/schemas";
import { getConfig } from "@app/lib/config/env";
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
import { groupBy } from "@app/lib/fn";
@@ -107,8 +107,7 @@ export const accessApprovalRequestServiceFactory = ({
actorId,
projectId: project.id,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
if (!membership) {
throw new ForbiddenRequestError({ message: "You are not a member of this project" });
@@ -217,7 +216,7 @@ export const accessApprovalRequestServiceFactory = ({
);
const requesterFullName = `${requestedByUser.firstName} ${requestedByUser.lastName}`;
const approvalUrl = `${cfg.SITE_URL}/projects/secret-management/${project.id}/approval`;
const approvalUrl = `${cfg.SITE_URL}/projects/${project.id}/secret-manager/approval`;
await triggerWorkflowIntegrationNotification({
input: {
@@ -290,8 +289,7 @@ export const accessApprovalRequestServiceFactory = ({
actorId,
projectId: project.id,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
if (!membership) {
throw new ForbiddenRequestError({ message: "You are not a member of this project" });
@@ -337,8 +335,7 @@ export const accessApprovalRequestServiceFactory = ({
actorId,
projectId: accessApprovalRequest.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
if (!membership) {
@@ -554,7 +551,7 @@ export const accessApprovalRequestServiceFactory = ({
bypassReason: bypassReason || "No reason provided",
secretPath: policy.secretPath || "/",
environment,
approvalUrl: `${cfg.SITE_URL}/projects/secret-management/${project.id}/approval`,
approvalUrl: `${cfg.SITE_URL}/projects/${project.id}/secret-manager/approval`,
requestType: "access"
},
template: SmtpTemplates.AccessSecretRequestBypassed
@@ -585,8 +582,7 @@ export const accessApprovalRequestServiceFactory = ({
actorId,
projectId: project.id,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
if (!membership) {
throw new ForbiddenRequestError({ message: "You are not a member of this project" });

View File

@@ -1,6 +1,5 @@
import { ForbiddenError } from "@casl/ability";
import { ActionProjectType } from "@app/db/schemas";
import { getConfig } from "@app/lib/config/env";
import { crypto } from "@app/lib/crypto/cryptography";
import { ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
@@ -38,8 +37,7 @@ export const assumePrivilegeServiceFactory = ({
actorId: actorPermissionDetails.id,
projectId,
actorAuthMethod: actorPermissionDetails.authMethod,
actorOrgId: actorPermissionDetails.orgId,
actionProjectType: ActionProjectType.Any
actorOrgId: actorPermissionDetails.orgId
});
if (targetActorType === ActorType.USER) {
@@ -60,8 +58,7 @@ export const assumePrivilegeServiceFactory = ({
actorId: targetActorId,
projectId,
actorAuthMethod: actorPermissionDetails.authMethod,
actorOrgId: actorPermissionDetails.orgId,
actionProjectType: ActionProjectType.Any
actorOrgId: actorPermissionDetails.orgId
});
const appCfg = getConfig();

View File

@@ -1,7 +1,6 @@
import { ForbiddenError } from "@casl/ability";
import { requestContext } from "@fastify/request-context";
import { ActionProjectType } from "@app/db/schemas";
import { getConfig } from "@app/lib/config/env";
import { BadRequestError } from "@app/lib/errors";
import { ActorType } from "@app/services/auth/auth-type";
@@ -38,8 +37,7 @@ export const auditLogServiceFactory = ({
actorId,
projectId: filter.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.AuditLogs);
} else {

View File

@@ -449,7 +449,6 @@ export enum EventType {
PIT_REVERT_COMMIT = "pit-revert-commit",
PIT_GET_FOLDER_STATE = "pit-get-folder-state",
PIT_COMPARE_FOLDER_STATES = "pit-compare-folder-states",
PIT_PROCESS_NEW_COMMIT_RAW = "pit-process-new-commit-raw",
SECRET_SCANNING_DATA_SOURCE_LIST = "secret-scanning-data-source-list",
SECRET_SCANNING_DATA_SOURCE_CREATE = "secret-scanning-data-source-create",
SECRET_SCANNING_DATA_SOURCE_UPDATE = "secret-scanning-data-source-update",
@@ -1547,9 +1546,8 @@ interface UpdateFolderEvent {
metadata: {
environment: string;
folderId: string;
oldFolderName?: string;
oldFolderName: string;
newFolderName: string;
newFolderDescription?: string;
folderPath: string;
};
}
@@ -3224,18 +3222,6 @@ interface PitCompareFolderStatesEvent {
};
}
interface PitProcessNewCommitRawEvent {
type: EventType.PIT_PROCESS_NEW_COMMIT_RAW;
metadata: {
projectId: string;
environment: string;
secretPath: string;
message: string;
approvalId?: string;
commitId?: string;
};
}
interface SecretScanningDataSourceListEvent {
type: EventType.SECRET_SCANNING_DATA_SOURCE_LIST;
metadata: {
@@ -3672,7 +3658,6 @@ export type Event =
| PitRevertCommitEvent
| PitCompareFolderStatesEvent
| PitGetFolderStateEvent
| PitProcessNewCommitRawEvent
| SecretScanningDataSourceListEvent
| SecretScanningDataSourceGetEvent
| SecretScanningDataSourceCreateEvent

View File

@@ -1,7 +1,6 @@
import { ForbiddenError } from "@casl/ability";
import * as x509 from "@peculiar/x509";
import { ActionProjectType } from "@app/db/schemas";
import { TCertificateAuthorityCrlDALFactory } from "@app/ee/services/certificate-authority-crl/certificate-authority-crl-dal";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
@@ -78,8 +77,7 @@ export const certificateAuthorityCrlServiceFactory = ({
actorId,
projectId: ca.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(

View File

@@ -1,7 +1,6 @@
import { ForbiddenError, subject } from "@casl/ability";
import RE2 from "re2";
import { ActionProjectType } from "@app/db/schemas";
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import {
@@ -85,8 +84,7 @@ export const dynamicSecretLeaseServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
const plan = await licenseService.getPlan(actorOrgId);
@@ -202,8 +200,7 @@ export const dynamicSecretLeaseServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
const { decryptor: secretManagerDecryptor } = await kmsService.createCipherPairWithDataKey({
@@ -300,8 +297,7 @@ export const dynamicSecretLeaseServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
const { decryptor: secretManagerDecryptor } = await kmsService.createCipherPairWithDataKey({
@@ -389,8 +385,7 @@ export const dynamicSecretLeaseServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
const folder = await folderDAL.findBySecretPath(projectId, environmentSlug, path);
@@ -437,8 +432,7 @@ export const dynamicSecretLeaseServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
const folder = await folderDAL.findBySecretPath(projectId, environmentSlug, path);

View File

@@ -1,6 +1,5 @@
import { ForbiddenError, subject } from "@casl/ability";
import { ActionProjectType } from "@app/db/schemas";
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import {
@@ -79,8 +78,7 @@ export const dynamicSecretServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -209,8 +207,7 @@ export const dynamicSecretServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
const plan = await licenseService.getPlan(actorOrgId);
@@ -361,8 +358,7 @@ export const dynamicSecretServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
const folder = await folderDAL.findBySecretPath(projectId, environmentSlug, path);
@@ -427,8 +423,7 @@ export const dynamicSecretServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
const folder = await folderDAL.findBySecretPath(projectId, environmentSlug, path);
@@ -492,8 +487,7 @@ export const dynamicSecretServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
// verify user has access to each env in request
@@ -536,8 +530,7 @@ export const dynamicSecretServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionDynamicSecretActions.ReadRootCredential,
@@ -585,8 +578,7 @@ export const dynamicSecretServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
const folder = await folderDAL.findBySecretPath(projectId, environmentSlug, path);
@@ -623,8 +615,7 @@ export const dynamicSecretServiceFactory = ({
actorId: actor.id,
projectId,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId: actor.orgId
});
const userAccessibleFolderMappings = folderMappings.filter(({ path, environment }) =>
@@ -668,8 +659,7 @@ export const dynamicSecretServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
const folders = await folderDAL.findBySecretPathMultiEnv(projectId, environmentSlugs, path);

View File

@@ -566,14 +566,6 @@ export const gatewayServiceFactory = ({
if (!gateway) throw new NotFoundError({ message: `Gateway with ID ${gatewayId} not found.` });
const orgGatewayConfig = await orgGatewayConfigDAL.findById(gateway.orgGatewayRootCaId);
const orgLicensePlan = await licenseService.getPlan(orgGatewayConfig.orgId);
if (!orgLicensePlan.gateway) {
throw new BadRequestError({
message: "Please upgrade your instance to Infisical's Enterprise plan to use gateways."
});
}
const { decryptor: orgKmsDecryptor } = await kmsService.createCipherPairWithDataKey({
type: KmsDataKey.Organization,
orgId: orgGatewayConfig.orgId

View File

@@ -1,7 +1,7 @@
import { ForbiddenError, subject } from "@casl/ability";
import { packRules } from "@casl/ability/extra";
import { ActionProjectType, TableName } from "@app/db/schemas";
import { TableName } from "@app/db/schemas";
import { BadRequestError, NotFoundError, PermissionBoundaryError } from "@app/lib/errors";
import { ms } from "@app/lib/ms";
import { validateHandlebarTemplate } from "@app/lib/template/validate-handlebars";
@@ -61,8 +61,7 @@ export const identityProjectAdditionalPrivilegeV2ServiceFactory = ({
actorId,
projectId: identityProjectMembership.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionIdentityActions.Edit,
@@ -73,8 +72,7 @@ export const identityProjectAdditionalPrivilegeV2ServiceFactory = ({
actorId: identityId,
projectId: identityProjectMembership.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
// we need to validate that the privilege given is not higher than the assigning users permission
@@ -160,8 +158,7 @@ export const identityProjectAdditionalPrivilegeV2ServiceFactory = ({
actorId,
projectId: identityProjectMembership.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionIdentityActions.Edit,
@@ -172,8 +169,7 @@ export const identityProjectAdditionalPrivilegeV2ServiceFactory = ({
actorId: identityProjectMembership.identityId,
projectId: identityProjectMembership.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
// we need to validate that the privilege given is not higher than the assigning users permission
@@ -260,8 +256,7 @@ export const identityProjectAdditionalPrivilegeV2ServiceFactory = ({
actorId,
projectId: identityProjectMembership.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionIdentityActions.Edit,
@@ -272,8 +267,7 @@ export const identityProjectAdditionalPrivilegeV2ServiceFactory = ({
actorId: identityProjectMembership.identityId,
projectId: identityProjectMembership.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
const permissionBoundary = validatePrivilegeChangeOperation(
membership.shouldUseNewPrivilegeSystem,
@@ -321,8 +315,7 @@ export const identityProjectAdditionalPrivilegeV2ServiceFactory = ({
actorId,
projectId: identityProjectMembership.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionIdentityActions.Read,
@@ -356,8 +349,7 @@ export const identityProjectAdditionalPrivilegeV2ServiceFactory = ({
actorId,
projectId: identityProjectMembership.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionIdentityActions.Read,
@@ -392,8 +384,7 @@ export const identityProjectAdditionalPrivilegeV2ServiceFactory = ({
actorId,
projectId: identityProjectMembership.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionIdentityActions.Read,

View File

@@ -1,7 +1,6 @@
import { ForbiddenError, MongoAbility, RawRuleOf, subject } from "@casl/ability";
import { PackRule, packRules, unpackRules } from "@casl/ability/extra";
import { ActionProjectType } from "@app/db/schemas";
import { BadRequestError, NotFoundError, PermissionBoundaryError } from "@app/lib/errors";
import { ms } from "@app/lib/ms";
import { validateHandlebarTemplate } from "@app/lib/template/validate-handlebars";
@@ -73,8 +72,7 @@ export const identityProjectAdditionalPrivilegeServiceFactory = ({
actorId,
projectId: identityProjectMembership.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -87,8 +85,7 @@ export const identityProjectAdditionalPrivilegeServiceFactory = ({
actorId: identityId,
projectId: identityProjectMembership.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
// we need to validate that the privilege given is not higher than the assigning users permission
@@ -175,8 +172,7 @@ export const identityProjectAdditionalPrivilegeServiceFactory = ({
actorId,
projectId: identityProjectMembership.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -189,8 +185,7 @@ export const identityProjectAdditionalPrivilegeServiceFactory = ({
actorId: identityProjectMembership.identityId,
projectId: identityProjectMembership.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
// we need to validate that the privilege given is not higher than the assigning users permission
@@ -293,8 +288,7 @@ export const identityProjectAdditionalPrivilegeServiceFactory = ({
actorId,
projectId: identityProjectMembership.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionIdentityActions.Edit,
@@ -306,8 +300,7 @@ export const identityProjectAdditionalPrivilegeServiceFactory = ({
actorId: identityProjectMembership.identityId,
projectId: identityProjectMembership.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
const permissionBoundary = validatePrivilegeChangeOperation(
membership.shouldUseNewPrivilegeSystem,
@@ -366,8 +359,7 @@ export const identityProjectAdditionalPrivilegeServiceFactory = ({
actorId,
projectId: identityProjectMembership.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionIdentityActions.Read,
@@ -409,8 +401,7 @@ export const identityProjectAdditionalPrivilegeServiceFactory = ({
actorId,
projectId: identityProjectMembership.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(

View File

@@ -1,7 +1,6 @@
import { ForbiddenError } from "@casl/ability";
import * as x509 from "@peculiar/x509";
import { ActionProjectType } from "@app/db/schemas";
import { crypto } from "@app/lib/crypto/cryptography";
import { BadRequestError, InternalServerError, NotFoundError } from "@app/lib/errors";
import { isValidIp } from "@app/lib/ip";
@@ -79,8 +78,7 @@ export const kmipServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.KMS
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -133,8 +131,7 @@ export const kmipServiceFactory = ({
actorId,
projectId: kmipClient.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.KMS
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -165,8 +162,7 @@ export const kmipServiceFactory = ({
actorId,
projectId: kmipClient.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.KMS
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -199,8 +195,7 @@ export const kmipServiceFactory = ({
actorId,
projectId: kmipClient.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.KMS
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionKmipActions.ReadClients, ProjectPermissionSub.Kmip);
@@ -221,8 +216,7 @@ export const kmipServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.KMS
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionKmipActions.ReadClients, ProjectPermissionSub.Kmip);
@@ -258,8 +252,7 @@ export const kmipServiceFactory = ({
actorId,
projectId: kmipClient.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.KMS
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(

View File

@@ -1,7 +1,6 @@
import { MongoAbility, RawRuleOf } from "@casl/ability";
import { MongoQuery } from "@ucast/mongo2js";
import { ActionProjectType } from "@app/db/schemas";
import { ActorAuthMethod, ActorType } from "@app/services/auth/auth-type";
import { OrgPermissionSet } from "./org-permission";
@@ -21,7 +20,6 @@ export type TGetUserProjectPermissionArg = {
userId: string;
projectId: string;
authMethod: ActorAuthMethod;
actionProjectType: ActionProjectType;
userOrgId?: string;
};
@@ -29,14 +27,12 @@ export type TGetIdentityProjectPermissionArg = {
identityId: string;
projectId: string;
identityOrgId?: string;
actionProjectType: ActionProjectType;
};
export type TGetServiceTokenProjectPermissionArg = {
serviceTokenId: string;
projectId: string;
actorOrgId?: string;
actionProjectType: ActionProjectType;
};
export type TGetProjectPermissionArg = {
@@ -45,7 +41,6 @@ export type TGetProjectPermissionArg = {
projectId: string;
actorAuthMethod: ActorAuthMethod;
actorOrgId?: string;
actionProjectType: ActionProjectType;
};
export type TPermissionServiceFactory = {
@@ -143,13 +138,7 @@ export type TPermissionServiceFactory = {
};
}
>;
getUserProjectPermission: ({
userId,
projectId,
authMethod,
userOrgId,
actionProjectType
}: TGetUserProjectPermissionArg) => Promise<{
getUserProjectPermission: ({ userId, projectId, authMethod, userOrgId }: TGetUserProjectPermissionArg) => Promise<{
permission: MongoAbility<ProjectPermissionSet, MongoQuery>;
membership: {
id: string;

View File

@@ -5,7 +5,6 @@ import { MongoQuery } from "@ucast/mongo2js";
import handlebars from "handlebars";
import {
ActionProjectType,
OrgMembershipRole,
ProjectMembershipRole,
ServiceTokenScopes,
@@ -214,8 +213,7 @@ export const permissionServiceFactory = ({
userId,
projectId,
authMethod,
userOrgId,
actionProjectType
userOrgId
}: TGetUserProjectPermissionArg): Promise<TProjectPermissionRT<ActorType.USER>> => {
const userProjectPermission = await permissionDAL.getProjectPermission(userId, projectId);
if (!userProjectPermission) throw new ForbiddenRequestError({ name: "User not a part of the specified project" });
@@ -242,12 +240,6 @@ export const permissionServiceFactory = ({
userProjectPermission.orgRole
);
if (actionProjectType !== ActionProjectType.Any && actionProjectType !== userProjectPermission.projectType) {
throw new BadRequestError({
message: `The project is of type ${userProjectPermission.projectType}. Operations of type ${actionProjectType} are not allowed.`
});
}
// join two permissions and pass to build the final permission set
const rolePermissions = userProjectPermission.roles?.map(({ role, permissions }) => ({ role, permissions })) || [];
const additionalPrivileges =
@@ -295,8 +287,7 @@ export const permissionServiceFactory = ({
const getIdentityProjectPermission = async ({
identityId,
projectId,
identityOrgId,
actionProjectType
identityOrgId
}: TGetIdentityProjectPermissionArg): Promise<TProjectPermissionRT<ActorType.IDENTITY>> => {
const identityProjectPermission = await permissionDAL.getProjectIdentityPermission(identityId, projectId);
if (!identityProjectPermission)
@@ -316,12 +307,6 @@ export const permissionServiceFactory = ({
throw new ForbiddenRequestError({ name: "Identity is not a member of the specified organization" });
}
if (actionProjectType !== ActionProjectType.Any && actionProjectType !== identityProjectPermission.projectType) {
throw new BadRequestError({
message: `The project is of type ${identityProjectPermission.projectType}. Operations of type ${actionProjectType} are not allowed.`
});
}
const rolePermissions =
identityProjectPermission.roles?.map(({ role, permissions }) => ({ role, permissions })) || [];
const additionalPrivileges =
@@ -376,8 +361,7 @@ export const permissionServiceFactory = ({
const getServiceTokenProjectPermission = async ({
serviceTokenId,
projectId,
actorOrgId,
actionProjectType
actorOrgId
}: TGetServiceTokenProjectPermissionArg) => {
const serviceToken = await serviceTokenDAL.findById(serviceTokenId);
if (!serviceToken) throw new NotFoundError({ message: `Service token with ID '${serviceTokenId}' not found` });
@@ -402,12 +386,6 @@ export const permissionServiceFactory = ({
});
}
if (actionProjectType !== ActionProjectType.Any && actionProjectType !== serviceTokenProject.type) {
throw new BadRequestError({
message: `The project is of type ${serviceTokenProject.type}. Operations of type ${actionProjectType} are not allowed.`
});
}
const scopes = ServiceTokenScopes.parse(serviceToken.scopes || []);
return {
permission: buildServiceTokenProjectPermission(scopes, serviceToken.permissions),
@@ -559,8 +537,7 @@ export const permissionServiceFactory = ({
actorId: inputActorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType
actorOrgId
}: TGetProjectPermissionArg): Promise<TProjectPermissionRT<T>> => {
let actor = inputActor;
let actorId = inputActorId;
@@ -581,22 +558,19 @@ export const permissionServiceFactory = ({
userId: actorId,
projectId,
authMethod: actorAuthMethod,
userOrgId: actorOrgId,
actionProjectType
userOrgId: actorOrgId
}) as Promise<TProjectPermissionRT<T>>;
case ActorType.SERVICE:
return getServiceTokenProjectPermission({
serviceTokenId: actorId,
projectId,
actorOrgId,
actionProjectType
actorOrgId
}) as Promise<TProjectPermissionRT<T>>;
case ActorType.IDENTITY:
return getIdentityProjectPermission({
identityId: actorId,
projectId,
identityOrgId: actorOrgId,
actionProjectType
identityOrgId: actorOrgId
}) as Promise<TProjectPermissionRT<T>>;
default:
throw new BadRequestError({

View File

@@ -1,53 +1,32 @@
/* eslint-disable no-await-in-loop */
import { ForbiddenError } from "@casl/ability";
import { ActionProjectType } from "@app/db/schemas";
import { Event, EventType } from "@app/ee/services/audit-log/audit-log-types";
import { ProjectPermissionCommitsActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
import { BadRequestError, NotFoundError } from "@app/lib/errors";
import { NotFoundError } from "@app/lib/errors";
import { logger } from "@app/lib/logger";
import { ActorAuthMethod, ActorType } from "@app/services/auth/auth-type";
import { TFolderCommitDALFactory } from "@app/services/folder-commit/folder-commit-dal";
import {
ResourceType,
TCommitResourceChangeDTO,
TFolderCommitServiceFactory
} from "@app/services/folder-commit/folder-commit-service";
import { ResourceType, TFolderCommitServiceFactory } from "@app/services/folder-commit/folder-commit-service";
import {
isFolderCommitChange,
isImportCommitChange,
isSecretCommitChange
} from "@app/services/folder-commit-changes/folder-commit-changes-dal";
import { TProjectDALFactory } from "@app/services/project/project-dal";
import { TProjectEnvDALFactory } from "@app/services/project-env/project-env-dal";
import { TSecretServiceFactory } from "@app/services/secret/secret-service";
import { TProcessNewCommitRawDTO } from "@app/services/secret/secret-types";
import { TSecretFolderDALFactory } from "@app/services/secret-folder/secret-folder-dal";
import { TSecretFolderServiceFactory } from "@app/services/secret-folder/secret-folder-service";
import { TSecretV2BridgeServiceFactory } from "@app/services/secret-v2-bridge/secret-v2-bridge-service";
import { SecretOperations, SecretUpdateMode } from "@app/services/secret-v2-bridge/secret-v2-bridge-types";
import { TSecretImportServiceFactory } from "@app/services/secret-import/secret-import-service";
import { TPermissionServiceFactory } from "../permission/permission-service-types";
import { TSecretApprovalPolicyServiceFactory } from "../secret-approval-policy/secret-approval-policy-service";
import { TSecretApprovalRequestServiceFactory } from "../secret-approval-request/secret-approval-request-service";
type TPitServiceFactoryDep = {
folderCommitService: TFolderCommitServiceFactory;
secretService: Pick<TSecretServiceFactory, "getSecretVersionsV2ByIds" | "getChangeVersions">;
folderService: Pick<
TSecretFolderServiceFactory,
"getFolderById" | "getFolderVersions" | "createManyFolders" | "updateManyFolders" | "deleteManyFolders"
>;
folderService: Pick<TSecretFolderServiceFactory, "getFolderById" | "getFolderVersions">;
secretImportService: Pick<TSecretImportServiceFactory, "getImportVersions">;
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
folderDAL: Pick<TSecretFolderDALFactory, "findSecretPathByFolderIds" | "findBySecretPath">;
folderDAL: Pick<TSecretFolderDALFactory, "findSecretPathByFolderIds">;
projectEnvDAL: Pick<TProjectEnvDALFactory, "findOne">;
secretApprovalRequestService: Pick<
TSecretApprovalRequestServiceFactory,
"generateSecretApprovalRequest" | "generateSecretApprovalRequestV2Bridge"
>;
secretApprovalPolicyService: Pick<TSecretApprovalPolicyServiceFactory, "getSecretApprovalPolicy">;
projectDAL: Pick<TProjectDALFactory, "checkProjectUpgradeStatus" | "findProjectBySlug" | "findById">;
secretV2BridgeService: TSecretV2BridgeServiceFactory;
folderCommitDAL: Pick<TFolderCommitDALFactory, "transaction">;
};
export type TPitServiceFactory = ReturnType<typeof pitServiceFactory>;
@@ -56,14 +35,10 @@ export const pitServiceFactory = ({
folderCommitService,
secretService,
folderService,
secretImportService,
permissionService,
folderDAL,
projectEnvDAL,
secretApprovalRequestService,
secretApprovalPolicyService,
projectDAL,
secretV2BridgeService,
folderCommitDAL
projectEnvDAL
}: TPitServiceFactoryDep) => {
const getCommitsCount = async ({
actor,
@@ -195,6 +170,12 @@ export const pitServiceFactory = ({
(Number.parseInt(change.folderVersion, 10) - 1).toString(),
change.folderChangeId
);
} else if (isImportCommitChange(change)) {
change.versions = await secretImportService.getImportVersions(
change,
(Number.parseInt(change.importVersion, 10) - 1).toString(),
change.importChangeId
);
}
}
@@ -349,8 +330,7 @@ export const pitServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(userPermission).throwUnlessCan(
@@ -421,6 +401,7 @@ export const pitServiceFactory = ({
success: true,
secretChangesCount: response.secretChangesCount,
folderChangesCount: response.folderChangesCount,
importChangesCount: response.importChangesCount,
totalChanges: response.totalChanges
};
};
@@ -501,347 +482,6 @@ export const pitServiceFactory = ({
});
};
const processNewCommitRaw = async ({
actorId,
projectId,
environment,
actor,
actorOrgId,
actorAuthMethod,
secretPath,
message,
changes = {
secrets: {
create: [],
update: [],
delete: []
},
folders: {
create: [],
update: [],
delete: []
}
}
}: {
actorId: string;
projectId: string;
environment: string;
actor: ActorType;
actorOrgId: string;
actorAuthMethod: ActorAuthMethod;
secretPath: string;
message: string;
changes: TProcessNewCommitRawDTO;
}) => {
const policy =
actor === ActorType.USER
? await secretApprovalPolicyService.getSecretApprovalPolicy(projectId, environment, secretPath)
: undefined;
const secretMutationEvents: Event[] = [];
const project = await projectDAL.findById(projectId);
if (project.enforceCapitalization) {
const caseViolatingSecretKeys = [
// Check create operations
...(changes.secrets?.create
?.filter((sec) => sec.secretKey !== sec.secretKey.toUpperCase())
.map((sec) => sec.secretKey) ?? []),
// Check update operations
...(changes.secrets?.update
?.filter((sec) => sec.newSecretName && sec.newSecretName !== sec.newSecretName.toUpperCase())
.map((sec) => sec.secretKey) ?? [])
];
if (caseViolatingSecretKeys.length) {
throw new BadRequestError({
message: `Secret names must be in UPPERCASE per project requirements: ${caseViolatingSecretKeys.join(
", "
)}. You can disable this requirement in project settings`
});
}
}
const response = await folderCommitDAL.transaction(async (trx) => {
const targetFolder = await folderDAL.findBySecretPath(projectId, environment, secretPath, trx);
if (!targetFolder)
throw new NotFoundError({
message: `Folder with path '${secretPath}' in environment with slug '${environment}' not found`,
name: "CreateManySecret"
});
const commitChanges: TCommitResourceChangeDTO[] = [];
const folderChanges: { create: string[]; update: string[]; delete: string[] } = {
create: [],
update: [],
delete: []
};
if ((changes.folders?.create?.length ?? 0) > 0) {
const createdFolders = await folderService.createManyFolders({
projectId,
actor,
actorId,
actorOrgId,
actorAuthMethod,
folders:
changes.folders?.create?.map((folder) => ({
name: folder.folderName,
environment,
path: secretPath,
description: folder.description
})) ?? [],
tx: trx,
commitChanges
});
const newFolderEvents = createdFolders.folders.map(
(folder) =>
({
type: EventType.CREATE_FOLDER,
metadata: {
environment,
folderId: folder.id,
folderName: folder.name,
folderPath: secretPath,
...(folder.description ? { description: folder.description } : {})
}
}) as Event
);
secretMutationEvents.push(...newFolderEvents);
folderChanges.create.push(...createdFolders.folders.map((folder) => folder.id));
}
if ((changes.folders?.update?.length ?? 0) > 0) {
const updatedFolders = await folderService.updateManyFolders({
projectId,
actor,
actorId,
actorOrgId,
actorAuthMethod,
folders:
changes.folders?.update?.map((folder) => ({
environment,
path: secretPath,
id: folder.id,
name: folder.folderName,
description: folder.description
})) ?? [],
tx: trx,
commitChanges
});
const updatedFolderEvents = updatedFolders.newFolders.map(
(folder) =>
({
type: EventType.UPDATE_FOLDER,
metadata: {
environment,
folderId: folder.id,
folderPath: secretPath,
newFolderName: folder.name,
newFolderDescription: folder.description
}
}) as Event
);
secretMutationEvents.push(...updatedFolderEvents);
folderChanges.update.push(...updatedFolders.newFolders.map((folder) => folder.id));
}
if ((changes.folders?.delete?.length ?? 0) > 0) {
const deletedFolders = await folderService.deleteManyFolders({
projectId,
actor,
actorId,
actorOrgId,
actorAuthMethod,
folders:
changes.folders?.delete?.map((folder) => ({
environment,
path: secretPath,
idOrName: folder.id
})) ?? [],
tx: trx,
commitChanges
});
const deletedFolderEvents = deletedFolders.folders.map(
(folder) =>
({
type: EventType.DELETE_FOLDER,
metadata: {
environment,
folderId: folder.id,
folderPath: secretPath,
folderName: folder.name
}
}) as Event
);
secretMutationEvents.push(...deletedFolderEvents);
folderChanges.delete.push(...deletedFolders.folders.map((folder) => folder.id));
}
if (policy) {
if (
(changes.secrets?.create?.length ?? 0) > 0 ||
(changes.secrets?.update?.length ?? 0) > 0 ||
(changes.secrets?.delete?.length ?? 0) > 0
) {
const approval = await secretApprovalRequestService.generateSecretApprovalRequestV2Bridge({
policy,
secretPath,
environment,
projectId,
actor,
actorId,
actorOrgId,
actorAuthMethod,
data: {
[SecretOperations.Create]:
changes.secrets?.create?.map((el) => ({
tagIds: el.tagIds,
secretValue: el.secretValue,
secretComment: el.secretComment,
metadata: el.metadata,
skipMultilineEncoding: el.skipMultilineEncoding,
secretKey: el.secretKey,
secretMetadata: el.secretMetadata
})) ?? [],
[SecretOperations.Update]:
changes.secrets?.update?.map((el) => ({
tagIds: el.tagIds,
newSecretName: el.newSecretName,
secretValue: el.secretValue,
secretComment: el.secretComment,
metadata: el.metadata,
skipMultilineEncoding: el.skipMultilineEncoding,
secretKey: el.secretKey,
secretMetadata: el.secretMetadata
})) ?? [],
[SecretOperations.Delete]:
changes.secrets?.delete?.map((el) => ({
secretKey: el.secretKey
})) ?? []
}
});
return {
approvalId: approval.id,
folderChanges,
secretMutationEvents
};
}
return {
folderChanges,
secretMutationEvents
};
}
if ((changes.secrets?.create?.length ?? 0) > 0) {
const newSecrets = await secretV2BridgeService.createManySecret({
secretPath,
environment,
projectId,
actorAuthMethod,
actorOrgId,
actor,
actorId,
secrets: changes.secrets?.create ?? [],
tx: trx,
commitChanges
});
secretMutationEvents.push({
type: EventType.CREATE_SECRETS,
metadata: {
environment,
secretPath,
secrets: newSecrets.map((secret) => ({
secretId: secret.id,
secretKey: secret.secretKey,
secretVersion: secret.version
}))
}
});
}
if ((changes.secrets?.update?.length ?? 0) > 0) {
const updatedSecrets = await secretV2BridgeService.updateManySecret({
secretPath,
environment,
projectId,
actorAuthMethod,
actorOrgId,
actor,
actorId,
secrets: changes.secrets?.update ?? [],
mode: SecretUpdateMode.FailOnNotFound,
tx: trx,
commitChanges
});
secretMutationEvents.push({
type: EventType.UPDATE_SECRETS,
metadata: {
environment,
secretPath,
secrets: updatedSecrets.map((secret) => ({
secretId: secret.id,
secretKey: secret.secretKey,
secretVersion: secret.version
}))
}
});
}
if ((changes.secrets?.delete?.length ?? 0) > 0) {
const deletedSecrets = await secretV2BridgeService.deleteManySecret({
secretPath,
environment,
projectId,
actorAuthMethod,
actorOrgId,
actor,
actorId,
secrets: changes.secrets?.delete ?? [],
tx: trx,
commitChanges
});
secretMutationEvents.push({
type: EventType.DELETE_SECRETS,
metadata: {
environment,
secretPath,
secrets: deletedSecrets.map((secret) => ({
secretId: secret.id,
secretKey: secret.secretKey,
secretVersion: secret.version
}))
}
});
}
if (commitChanges?.length > 0) {
const commit = await folderCommitService.createCommit(
{
actor: {
type: actor || ActorType.PLATFORM,
metadata: {
id: actorId
}
},
message,
folderId: targetFolder.id,
changes: commitChanges
},
trx
);
return {
folderChanges,
commitId: commit?.id,
secretMutationEvents
};
}
return {
folderChanges,
secretMutationEvents
};
});
return response;
};
return {
getCommitsCount,
getCommitsForFolder,
@@ -849,7 +489,6 @@ export const pitServiceFactory = ({
compareCommitChanges,
rollbackToCommit,
revertCommit,
getFolderStateAtCommit,
processNewCommitRaw
getFolderStateAtCommit
};
};

View File

@@ -1,4 +1,3 @@
import { ProjectType } from "@app/db/schemas";
import {
InfisicalProjectTemplate,
TUnpackedPermission
@@ -7,21 +6,18 @@ import { getPredefinedRoles } from "@app/services/project-role/project-role-fns"
import { ProjectTemplateDefaultEnvironments } from "./project-template-constants";
export const getDefaultProjectTemplate = (orgId: string, type: ProjectType) => ({
export const getDefaultProjectTemplate = (orgId: string) => ({
id: "b11b49a9-09a9-4443-916a-4246f9ff2c69", // random ID to appease zod
type,
name: InfisicalProjectTemplate.Default,
createdAt: new Date(),
updatedAt: new Date(),
description: `Infisical's ${type} default project template`,
environments: type === ProjectType.SecretManager ? ProjectTemplateDefaultEnvironments : null,
roles: [...getPredefinedRoles({ projectId: "project-template", projectType: type })].map(
({ name, slug, permissions }) => ({
name,
slug,
permissions: permissions as TUnpackedPermission[]
})
),
description: `Infisical's default project template`,
environments: ProjectTemplateDefaultEnvironments,
roles: getPredefinedRoles({ projectId: "project-template" }) as Array<{
name: string;
slug: string;
permissions: TUnpackedPermission[];
}>,
orgId
});

View File

@@ -1,7 +1,7 @@
import { ForbiddenError } from "@casl/ability";
import { packRules } from "@casl/ability/extra";
import { ProjectType, TProjectTemplates } from "@app/db/schemas";
import { TProjectTemplates } from "@app/db/schemas";
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
@@ -29,13 +29,11 @@ const $unpackProjectTemplate = ({ roles, environments, ...rest }: TProjectTempla
...rest,
environments: environments as TProjectTemplateEnvironment[],
roles: [
...getPredefinedRoles({ projectId: "project-template", projectType: rest.type as ProjectType }).map(
({ name, slug, permissions }) => ({
name,
slug,
permissions: permissions as TUnpackedPermission[]
})
),
...getPredefinedRoles({ projectId: "project-template" }).map(({ name, slug, permissions }) => ({
name,
slug,
permissions: permissions as TUnpackedPermission[]
})),
...(roles as TProjectTemplateRole[]).map((role) => ({
...role,
permissions: unpackPermissions(role.permissions)
@@ -48,10 +46,7 @@ export const projectTemplateServiceFactory = ({
permissionService,
projectTemplateDAL
}: TProjectTemplatesServiceFactoryDep): TProjectTemplateServiceFactory => {
const listProjectTemplatesByOrg: TProjectTemplateServiceFactory["listProjectTemplatesByOrg"] = async (
actor,
type
) => {
const listProjectTemplatesByOrg: TProjectTemplateServiceFactory["listProjectTemplatesByOrg"] = async (actor) => {
const plan = await licenseService.getPlan(actor.orgId);
if (!plan.projectTemplates)
@@ -70,14 +65,11 @@ export const projectTemplateServiceFactory = ({
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.ProjectTemplates);
const projectTemplates = await projectTemplateDAL.find({
orgId: actor.orgId,
...(type ? { type } : {})
orgId: actor.orgId
});
return [
...(type
? [getDefaultProjectTemplate(actor.orgId, type)]
: Object.values(ProjectType).map((projectType) => getDefaultProjectTemplate(actor.orgId, projectType))),
getDefaultProjectTemplate(actor.orgId),
...projectTemplates.map((template) => $unpackProjectTemplate(template))
];
};
@@ -142,7 +134,7 @@ export const projectTemplateServiceFactory = ({
};
const createProjectTemplate: TProjectTemplateServiceFactory["createProjectTemplate"] = async (
{ roles, environments, type, ...params },
{ roles, environments, ...params },
actor
) => {
const plan = await licenseService.getPlan(actor.orgId);
@@ -162,10 +154,6 @@ export const projectTemplateServiceFactory = ({
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.ProjectTemplates);
if (environments && type !== ProjectType.SecretManager) {
throw new BadRequestError({ message: "Cannot configure environments for non-SecretManager project templates" });
}
if (environments && plan.environmentLimit !== null && environments.length > plan.environmentLimit) {
throw new BadRequestError({
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
@@ -188,10 +176,8 @@ export const projectTemplateServiceFactory = ({
const projectTemplate = await projectTemplateDAL.create({
...params,
roles: JSON.stringify(roles.map((role) => ({ ...role, permissions: packRules(role.permissions) }))),
environments:
type === ProjectType.SecretManager ? JSON.stringify(environments ?? ProjectTemplateDefaultEnvironments) : null,
orgId: actor.orgId,
type
environments: environments ? JSON.stringify(environments ?? ProjectTemplateDefaultEnvironments) : null,
orgId: actor.orgId
});
return $unpackProjectTemplate(projectTemplate);
@@ -222,11 +208,6 @@ export const projectTemplateServiceFactory = ({
);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.ProjectTemplates);
if (projectTemplate.type !== ProjectType.SecretManager && environments)
throw new BadRequestError({ message: "Cannot configure environments for non-SecretManager project templates" });
if (projectTemplate.type === ProjectType.SecretManager && environments === null)
throw new BadRequestError({ message: "Environments cannot be removed for SecretManager project templates" });
if (environments && plan.environmentLimit !== null && environments.length > plan.environmentLimit) {
throw new BadRequestError({

View File

@@ -1,6 +1,6 @@
import { z } from "zod";
import { ProjectMembershipRole, ProjectType, TProjectEnvironments } from "@app/db/schemas";
import { ProjectMembershipRole, TProjectEnvironments } from "@app/db/schemas";
import { TProjectPermissionV2Schema } from "@app/ee/services/permission/project-permission";
import { OrgServiceActor } from "@app/lib/types";
import { UnpackedPermissionSchema } from "@app/server/routes/sanitizedSchema/permission";
@@ -15,7 +15,6 @@ export type TProjectTemplateRole = {
export type TCreateProjectTemplateDTO = {
name: string;
type: ProjectType;
description?: string;
roles: TProjectTemplateRole[];
environments?: TProjectTemplateEnvironment[] | null;
@@ -30,15 +29,11 @@ export enum InfisicalProjectTemplate {
}
export type TProjectTemplateServiceFactory = {
listProjectTemplatesByOrg: (
actor: OrgServiceActor,
type?: ProjectType
) => Promise<
listProjectTemplatesByOrg: (actor: OrgServiceActor) => Promise<
(
| {
id: string;
name: InfisicalProjectTemplate;
type: string;
createdAt: Date;
updatedAt: Date;
description: string;
@@ -63,7 +58,6 @@ export type TProjectTemplateServiceFactory = {
}
| {
environments: TProjectTemplateEnvironment[];
type: string;
roles: {
permissions: {
action: string[];
@@ -100,7 +94,6 @@ export type TProjectTemplateServiceFactory = {
}[];
name: string;
orgId: string;
type: string;
id: string;
createdAt: Date;
updatedAt: Date;
@@ -125,7 +118,6 @@ export type TProjectTemplateServiceFactory = {
name: string;
orgId: string;
id: string;
type: string;
createdAt: Date;
updatedAt: Date;
description?: string | null | undefined;
@@ -148,7 +140,6 @@ export type TProjectTemplateServiceFactory = {
name: string;
orgId: string;
id: string;
type: string;
createdAt: Date;
updatedAt: Date;
description?: string | null | undefined;
@@ -171,7 +162,6 @@ export type TProjectTemplateServiceFactory = {
}[];
name: string;
orgId: string;
type: string;
id: string;
createdAt: Date;
updatedAt: Date;
@@ -194,7 +184,6 @@ export type TProjectTemplateServiceFactory = {
name: string;
}[];
name: string;
type: string;
orgId: string;
id: string;
createdAt: Date;

View File

@@ -1,7 +1,7 @@
import { ForbiddenError, MongoAbility, RawRuleOf } from "@casl/ability";
import { PackRule, packRules, unpackRules } from "@casl/ability/extra";
import { ActionProjectType, TableName } from "@app/db/schemas";
import { TableName } from "@app/db/schemas";
import { BadRequestError, NotFoundError, PermissionBoundaryError } from "@app/lib/errors";
import { ms } from "@app/lib/ms";
import { validateHandlebarTemplate } from "@app/lib/template/validate-handlebars";
@@ -61,8 +61,7 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({
actorId,
projectId: projectMembership.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionMemberActions.Edit, ProjectPermissionSub.Member);
const { permission: targetUserPermission, membership } = await permissionService.getProjectPermission({
@@ -70,8 +69,7 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({
actorId: projectMembership.userId,
projectId: projectMembership.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
// we need to validate that the privilege given is not higher than the assigning users permission
@@ -166,8 +164,7 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({
actorId,
projectId: projectMembership.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionMemberActions.Edit, ProjectPermissionSub.Member);
const { permission: targetUserPermission } = await permissionService.getProjectPermission({
@@ -175,8 +172,7 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({
actorId: projectMembership.userId,
projectId: projectMembership.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
// we need to validate that the privilege given is not higher than the assigning users permission
@@ -276,8 +272,7 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({
actorId,
projectId: projectMembership.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionMemberActions.Edit, ProjectPermissionSub.Member);
@@ -322,8 +317,7 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({
actorId,
projectId: projectMembership.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionMemberActions.Read, ProjectPermissionSub.Member);
@@ -349,8 +343,7 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({
actorId,
projectId: projectMembership.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionMemberActions.Read, ProjectPermissionSub.Member);

View File

@@ -1,7 +1,6 @@
import { ForbiddenError } from "@casl/ability";
import picomatch from "picomatch";
import { ActionProjectType } from "@app/db/schemas";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
import { BadRequestError, NotFoundError } from "@app/lib/errors";
@@ -111,8 +110,7 @@ export const secretApprovalPolicyServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Create,
@@ -306,8 +304,7 @@ export const secretApprovalPolicyServiceFactory = ({
actorId,
projectId: secretApprovalPolicy.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.SecretApproval);
@@ -462,8 +459,7 @@ export const secretApprovalPolicyServiceFactory = ({
actorId,
projectId: sapPolicy.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Delete,
@@ -502,8 +498,7 @@ export const secretApprovalPolicyServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretApproval);
@@ -547,8 +542,7 @@ export const secretApprovalPolicyServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
return getSecretApprovalPolicy(projectId, environment, secretPath);
@@ -574,8 +568,7 @@ export const secretApprovalPolicyServiceFactory = ({
actorId,
projectId: sapPolicy.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretApproval);

View File

@@ -36,7 +36,7 @@ export const sendApprovalEmailsFn = async ({
firstName: reviewerUser.firstName,
projectName: project.name,
organizationName: project.organization.name,
approvalUrl: `${cfg.SITE_URL}/projects/secret-management/${project.id}/approval?requestId=${secretApprovalRequest.id}`
approvalUrl: `${cfg.SITE_URL}/projects/${project.id}/secret-manager/approval?requestId=${secretApprovalRequest.id}`
},
template: SmtpTemplates.SecretApprovalRequestNeedsReview
});

View File

@@ -1,9 +1,7 @@
/* eslint-disable no-nested-ternary */
import { ForbiddenError, subject } from "@casl/ability";
import { Knex } from "knex";
import {
ActionProjectType,
ProjectMembershipRole,
SecretEncryptionAlgo,
SecretKeyEncoding,
@@ -185,8 +183,7 @@ export const secretApprovalRequestServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
const count = await secretApprovalRequestDAL.findProjectRequestCount(projectId, actorId, policyId);
@@ -213,8 +210,7 @@ export const secretApprovalRequestServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
const { shouldUseSecretV2Bridge } = await projectBotService.getBotKey(projectId);
@@ -266,8 +262,7 @@ export const secretApprovalRequestServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
if (
!hasRole(ProjectMembershipRole.Admin) &&
@@ -416,8 +411,7 @@ export const secretApprovalRequestServiceFactory = ({
actorId,
projectId: secretApprovalRequest.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
if (
!hasRole(ProjectMembershipRole.Admin) &&
@@ -486,8 +480,7 @@ export const secretApprovalRequestServiceFactory = ({
actorId,
projectId: secretApprovalRequest.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
if (
!hasRole(ProjectMembershipRole.Admin) &&
@@ -543,8 +536,7 @@ export const secretApprovalRequestServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
if (
@@ -962,7 +954,7 @@ export const secretApprovalRequestServiceFactory = ({
bypassReason,
secretPath: policy.secretPath,
environment: env.name,
approvalUrl: `${cfg.SITE_URL}/projects/secret-management/${project.id}/approval`
approvalUrl: `${cfg.SITE_URL}/projects/${project.id}/secret-manager/approval`
},
template: SmtpTemplates.AccessSecretRequestBypassed
});
@@ -1096,8 +1088,7 @@ export const secretApprovalRequestServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
throwIfMissingSecretReadValueOrDescribePermission(permission, ProjectPermissionSecretActions.ReadValue, {
@@ -1377,9 +1368,8 @@ export const secretApprovalRequestServiceFactory = ({
policy,
projectId,
secretPath,
environment,
trx: providedTx
}: TGenerateSecretApprovalRequestV2BridgeDTO & { trx?: Knex }) => {
environment
}: TGenerateSecretApprovalRequestV2BridgeDTO) => {
if (actor === ActorType.SERVICE || actor === ActorType.Machine)
throw new BadRequestError({ message: "Cannot use service token or machine token over protected branches" });
@@ -1388,8 +1378,7 @@ export const secretApprovalRequestServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
const folder = await folderDAL.findBySecretPath(projectId, environment, secretPath);
if (!folder)
@@ -1606,7 +1595,7 @@ export const secretApprovalRequestServiceFactory = ({
);
});
const executeApprovalRequestCreation = async (tx: Knex) => {
const secretApprovalRequest = await secretApprovalRequestDAL.transaction(async (tx) => {
const doc = await secretApprovalRequestDAL.create(
{
folderId,
@@ -1668,11 +1657,7 @@ export const secretApprovalRequestServiceFactory = ({
}
return { ...doc, commits: approvalCommits };
};
const secretApprovalRequest = providedTx
? await executeApprovalRequestCreation(providedTx)
: await secretApprovalRequestDAL.transaction(executeApprovalRequestCreation);
});
const user = await userDAL.findById(actorId);
const env = await projectEnvDAL.findOne({ id: policy.envId });

View File

@@ -10,7 +10,7 @@ import { logger } from "@app/lib/logger";
import { alphaNumericNanoId } from "@app/lib/nanoid";
import { QueueName, TQueueServiceFactory } from "@app/queue";
import { ActorType } from "@app/services/auth/auth-type";
import { TFolderCommitServiceFactory } from "@app/services/folder-commit/folder-commit-service";
import { CommitType, TFolderCommitServiceFactory } from "@app/services/folder-commit/folder-commit-service";
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
import { KmsDataKey } from "@app/services/kms/kms-types";
import { TProjectBotServiceFactory } from "@app/services/project-bot/project-bot-service";
@@ -216,7 +216,7 @@ export const secretReplicationServiceFactory = ({
importEnv: folder.envId
});
// CASE: normal mode <- link import <- replicated import
// CASE: normal mode <- link import <- replicated import
const nonReplicatedDestinationImports = destinationSecretImports.filter(({ isReplication }) => !isReplication);
if (nonReplicatedDestinationImports.length) {
// keep calling sync secret for all the imports made
@@ -327,6 +327,7 @@ export const secretReplicationServiceFactory = ({
name: getReplicationFolderName(destinationSecretImport.id),
isReserved: true
});
if (!destinationReplicationFolder) {
destinationReplicationFolder = await folderDAL.create({
parentId: destinationFolder.id,
@@ -384,10 +385,10 @@ export const secretReplicationServiceFactory = ({
.filter(({ key }) => !sourceSecretsGroupByKey[key]?.[0])
.map((el) => ({ ...el, operation: SecretOperations.Delete }));
const isEmtpy =
const isEmpty =
locallyCreatedSecrets.length + locallyUpdatedSecrets.length + locallyDeletedSecrets.length === 0;
// eslint-disable-next-line
if (isEmtpy) continue;
if (isEmpty) continue;
const policy = await secretApprovalPolicyService.getSecretApprovalPolicy(
projectId,
@@ -445,6 +446,7 @@ export const secretReplicationServiceFactory = ({
if (locallyCreatedSecrets.length) {
await fnSecretV2BridgeBulkInsert({
folderId: destinationReplicationFolderId,
parentFolderId: destinationFolder.id,
orgId,
secretVersionDAL: secretVersionV2BridgeDAL,
secretDAL: secretV2BridgeDAL,
@@ -471,6 +473,7 @@ export const secretReplicationServiceFactory = ({
await fnSecretV2BridgeBulkUpdate({
orgId,
folderId: destinationReplicationFolderId,
parentFolderId: destinationFolder.id,
secretVersionDAL: secretVersionV2BridgeDAL,
folderCommitService,
secretDAL: secretV2BridgeDAL,
@@ -508,6 +511,52 @@ export const secretReplicationServiceFactory = ({
},
tx
);
const secretVersions = await secretVersionV2BridgeDAL.findLatestVersionMany(
destinationReplicationFolderId,
locallyDeletedSecrets.map(({ id }) => id)
);
const commitChanges = Object.entries(secretVersions)
.filter(([, { type }]) => type === SecretType.Shared)
.map(([, sv]) => ({
type: CommitType.DELETE,
secretVersionId: sv.id
}));
if (commitChanges.length > 0) {
const commit = await folderCommitService.createCommit(
{
actor: {
type: ActorType.PLATFORM
},
message: "Secret Deleted",
folderId: destinationReplicationFolderId,
changes: commitChanges
},
tx
);
if (commit) {
await folderCommitService.createCommit(
{
actor: {
type: ActorType.PLATFORM
},
message: "Secret Deleted Through Import",
folderId: destinationFolder.id,
changes: [
{
type: CommitType.ADD,
isUpdate: true,
reservedFolderCommitId: commit.id
}
]
},
tx
);
}
}
}
});

View File

@@ -2,7 +2,7 @@ import { ForbiddenError, subject } from "@casl/ability";
import { Knex } from "knex";
import isEqual from "lodash.isequal";
import { ActionProjectType, SecretType, TableName } from "@app/db/schemas";
import { SecretType, TableName } from "@app/db/schemas";
import { EventType, TAuditLogServiceFactory } from "@app/ee/services/audit-log/audit-log-types";
import { TGatewayServiceFactory } from "@app/ee/services/gateway/gateway-service";
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
@@ -223,7 +223,7 @@ export const secretRotationV2ServiceFactory = ({
actorId: actor.id,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretManager,
projectId
});
@@ -274,7 +274,7 @@ export const secretRotationV2ServiceFactory = ({
actorId: actor.id,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretManager,
projectId
});
@@ -320,7 +320,7 @@ export const secretRotationV2ServiceFactory = ({
actorId: actor.id,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretManager,
projectId
});
@@ -385,7 +385,7 @@ export const secretRotationV2ServiceFactory = ({
actorId: actor.id,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretManager,
projectId
});
@@ -429,7 +429,7 @@ export const secretRotationV2ServiceFactory = ({
actorId: actor.id,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretManager,
projectId
});
@@ -631,7 +631,7 @@ export const secretRotationV2ServiceFactory = ({
actorId: actor.id,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretManager,
projectId
});
@@ -781,7 +781,7 @@ export const secretRotationV2ServiceFactory = ({
actorId: actor.id,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretManager,
projectId
});
@@ -1113,7 +1113,7 @@ export const secretRotationV2ServiceFactory = ({
actorId: actor.id,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretManager,
projectId
});
@@ -1160,7 +1160,7 @@ export const secretRotationV2ServiceFactory = ({
actorId: actor.id,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretManager,
projectId
});
@@ -1212,7 +1212,7 @@ export const secretRotationV2ServiceFactory = ({
actorId: actor.id,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretManager,
projectId
});
@@ -1328,8 +1328,7 @@ export const secretRotationV2ServiceFactory = ({
actorId: actor.id,
projectId,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId: actor.orgId
});
const permissiveFolderMappings = folderMappings.filter(({ path, environment }) =>

View File

@@ -1,7 +1,7 @@
import { ForbiddenError, subject } from "@casl/ability";
import Ajv from "ajv";
import { ActionProjectType, ProjectVersion, TableName } from "@app/db/schemas";
import { ProjectVersion, TableName } from "@app/db/schemas";
import { crypto, SymmetricKeySize } from "@app/lib/crypto/cryptography";
import { BadRequestError, NotFoundError } from "@app/lib/errors";
import { TProjectPermission } from "@app/lib/types";
@@ -66,8 +66,7 @@ export const secretRotationServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionSecretRotationActions.Read,
@@ -98,8 +97,7 @@ export const secretRotationServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionSecretRotationActions.Read,
@@ -215,8 +213,7 @@ export const secretRotationServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionSecretRotationActions.Read,
@@ -266,8 +263,7 @@ export const secretRotationServiceFactory = ({
actorId,
projectId: project.id,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionSecretRotationActions.Edit,
@@ -287,8 +283,7 @@ export const secretRotationServiceFactory = ({
actorId,
projectId: doc.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionSecretRotationActions.Delete,

View File

@@ -567,18 +567,14 @@ export const secretScanningV2QueueServiceFactory = async ({
const projectMembers = await projectMembershipDAL.findAllProjectMembers(projectId);
const project = await projectDAL.findById(projectId);
const recipients = projectMembers.filter((member) => {
const isAdmin = member.roles.some((role) => role.role === ProjectMembershipRole.Admin);
const isCompleted = payload.status === SecretScanningScanStatus.Completed;
// We assume that the committer is one of the project members
const isCommitter = isCompleted && payload.authorEmail === member.user.email;
return isAdmin || isCommitter;
});
const projectAdmins = projectMembers.filter((member) =>
member.roles.some((role) => role.role === ProjectMembershipRole.Admin)
);
const timestamp = new Date().toISOString();
await smtpService.sendMail({
recipients: recipients.map((member) => member.user.email!).filter(Boolean),
recipients: projectAdmins.map((member) => member.user.email!).filter(Boolean),
template:
payload.status === SecretScanningScanStatus.Completed
? SmtpTemplates.SecretScanningV2SecretsDetected

View File

@@ -1,7 +1,6 @@
import { ForbiddenError } from "@casl/ability";
import { join } from "path";
import { ActionProjectType } from "@app/db/schemas";
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import {
@@ -95,7 +94,7 @@ export const secretScanningV2ServiceFactory = ({
actorId: actor.id,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretScanning,
projectId
});
@@ -157,7 +156,7 @@ export const secretScanningV2ServiceFactory = ({
actorId: actor.id,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretScanning,
projectId: dataSource.projectId
});
@@ -202,7 +201,7 @@ export const secretScanningV2ServiceFactory = ({
actorId: actor.id,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretScanning,
projectId
});
@@ -236,7 +235,7 @@ export const secretScanningV2ServiceFactory = ({
actorId: actor.id,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretScanning,
projectId: payload.projectId
});
@@ -349,7 +348,7 @@ export const secretScanningV2ServiceFactory = ({
actorId: actor.id,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretScanning,
projectId: dataSource.projectId
});
@@ -402,7 +401,6 @@ export const secretScanningV2ServiceFactory = ({
actorId: actor.id,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretScanning,
projectId: dataSource.projectId
});
@@ -476,7 +474,7 @@ export const secretScanningV2ServiceFactory = ({
actorId: actor.id,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretScanning,
projectId: dataSource.projectId
});
@@ -540,7 +538,7 @@ export const secretScanningV2ServiceFactory = ({
actorId: actor.id,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretScanning,
projectId: dataSource.projectId
});
@@ -585,7 +583,7 @@ export const secretScanningV2ServiceFactory = ({
actorId: actor.id,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretScanning,
projectId: dataSource.projectId
});
@@ -628,7 +626,7 @@ export const secretScanningV2ServiceFactory = ({
actorId: actor.id,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretScanning,
projectId: dataSource.projectId
});
@@ -671,7 +669,7 @@ export const secretScanningV2ServiceFactory = ({
actorId: actor.id,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretScanning,
projectId: dataSource.projectId
});
@@ -704,7 +702,7 @@ export const secretScanningV2ServiceFactory = ({
actorId: actor.id,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretScanning,
projectId
});
@@ -738,7 +736,7 @@ export const secretScanningV2ServiceFactory = ({
actorId: actor.id,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretScanning,
projectId
});
@@ -778,7 +776,7 @@ export const secretScanningV2ServiceFactory = ({
actorId: actor.id,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretScanning,
projectId: finding.projectId
});
@@ -809,7 +807,7 @@ export const secretScanningV2ServiceFactory = ({
actorId: actor.id,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretScanning,
projectId
});
@@ -844,7 +842,7 @@ export const secretScanningV2ServiceFactory = ({
actorId: actor.id,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretScanning,
projectId
});

View File

@@ -2,7 +2,7 @@
// akhilmhdh: I did this, quite strange bug with eslint. Everything do have a type stil has this error
import { ForbiddenError } from "@casl/ability";
import { ActionProjectType, TableName, TSecretTagJunctionInsert, TSecretV2TagJunctionInsert } from "@app/db/schemas";
import { TableName, TSecretTagJunctionInsert, TSecretV2TagJunctionInsert } from "@app/db/schemas";
import { crypto, SymmetricKeySize } from "@app/lib/crypto/cryptography";
import { InternalServerError, NotFoundError } from "@app/lib/errors";
import { groupBy } from "@app/lib/fn";
@@ -103,8 +103,7 @@ export const secretSnapshotServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback);
@@ -140,8 +139,7 @@ export const secretSnapshotServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback);
@@ -169,8 +167,7 @@ export const secretSnapshotServiceFactory = ({
actorId,
projectId: snapshot.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback);
@@ -394,8 +391,7 @@ export const secretSnapshotServiceFactory = ({
actorId,
projectId: snapshot.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Create,

View File

@@ -1,6 +1,5 @@
import { ForbiddenError } from "@casl/ability";
import { ActionProjectType } from "@app/db/schemas";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
import { BadRequestError, NotFoundError } from "@app/lib/errors";
@@ -59,8 +58,7 @@ export const sshCertificateTemplateServiceFactory = ({
actorId,
projectId: ca.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SSH
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -132,8 +130,7 @@ export const sshCertificateTemplateServiceFactory = ({
actorId,
projectId: certTemplate.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SSH
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -201,8 +198,7 @@ export const sshCertificateTemplateServiceFactory = ({
actorId,
projectId: certificateTemplate.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SSH
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -228,8 +224,7 @@ export const sshCertificateTemplateServiceFactory = ({
actorId,
projectId: certTemplate.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SSH
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(

View File

@@ -1,6 +1,5 @@
import { ForbiddenError } from "@casl/ability";
import { ActionProjectType } from "@app/db/schemas";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
import { TSshHostDALFactory } from "@app/ee/services/ssh-host/ssh-host-dal";
@@ -80,8 +79,7 @@ export const sshHostGroupServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SSH
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.SshHostGroups);
@@ -173,8 +171,7 @@ export const sshHostGroupServiceFactory = ({
actorId,
projectId: sshHostGroup.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SSH
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.SshHostGroups);
@@ -270,8 +267,7 @@ export const sshHostGroupServiceFactory = ({
actorId,
projectId: sshHostGroup.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SSH
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SshHostGroups);
@@ -294,8 +290,7 @@ export const sshHostGroupServiceFactory = ({
actorId,
projectId: sshHostGroup.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SSH
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Delete, ProjectPermissionSub.SshHostGroups);
@@ -321,8 +316,7 @@ export const sshHostGroupServiceFactory = ({
actorId,
projectId: sshHostGroup.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SSH
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SshHostGroups);
@@ -360,8 +354,7 @@ export const sshHostGroupServiceFactory = ({
actorId,
projectId: sshHostGroup.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SSH
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.SshHostGroups);
@@ -400,8 +393,7 @@ export const sshHostGroupServiceFactory = ({
actorId,
projectId: sshHostGroup.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SSH
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.SshHostGroups);

View File

@@ -1,6 +1,5 @@
import { Knex } from "knex";
import { ActionProjectType } from "@app/db/schemas";
import { BadRequestError } from "@app/lib/errors";
import { ProjectPermissionSshHostActions, ProjectPermissionSub } from "../permission/project-permission";
@@ -63,8 +62,7 @@ export const createSshLoginMappings = async ({
userId: user.id,
projectId,
authMethod: actorAuthMethod,
userOrgId: actorOrgId,
actionProjectType: ActionProjectType.SSH
userOrgId: actorOrgId
});
}

View File

@@ -1,6 +1,5 @@
import { ForbiddenError, subject } from "@casl/ability";
import { ActionProjectType } from "@app/db/schemas";
import { TGroupDALFactory } from "@app/ee/services/group/group-dal";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { ProjectPermissionSshHostActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
@@ -112,8 +111,7 @@ export const sshHostServiceFactory = ({
actorId,
projectId: project.id,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SSH
actorOrgId
});
const projectHosts = await sshHostDAL.findUserAccessibleSshHosts([project.id], actorId);
@@ -146,8 +144,7 @@ export const sshHostServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SSH
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -276,8 +273,7 @@ export const sshHostServiceFactory = ({
actorId,
projectId: host.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SSH
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -338,8 +334,7 @@ export const sshHostServiceFactory = ({
actorId,
projectId: host.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SSH
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -367,8 +362,7 @@ export const sshHostServiceFactory = ({
actorId,
projectId: host.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SSH
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -407,8 +401,7 @@ export const sshHostServiceFactory = ({
actorId,
projectId: host.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SSH
actorOrgId
});
const internalPrincipals = await convertActorToPrincipals({
@@ -527,8 +520,7 @@ export const sshHostServiceFactory = ({
actorId,
projectId: host.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SSH
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(

View File

@@ -1,6 +1,5 @@
import { ForbiddenError } from "@casl/ability";
import { ActionProjectType } from "@app/db/schemas";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
import { TSshCertificateAuthorityDALFactory } from "@app/ee/services/ssh/ssh-certificate-authority-dal";
@@ -73,8 +72,7 @@ export const sshCertificateAuthorityServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SSH
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -109,8 +107,7 @@ export const sshCertificateAuthorityServiceFactory = ({
actorId,
projectId: ca.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SSH
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -178,8 +175,7 @@ export const sshCertificateAuthorityServiceFactory = ({
actorId,
projectId: ca.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SSH
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -217,8 +213,7 @@ export const sshCertificateAuthorityServiceFactory = ({
actorId,
projectId: ca.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SSH
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -259,8 +254,7 @@ export const sshCertificateAuthorityServiceFactory = ({
actorId,
projectId: sshCertificateTemplate.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SSH
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -381,8 +375,7 @@ export const sshCertificateAuthorityServiceFactory = ({
actorId,
projectId: sshCertificateTemplate.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SSH
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -479,8 +472,7 @@ export const sshCertificateAuthorityServiceFactory = ({
actorId,
projectId: ca.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SSH
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(

View File

@@ -1,6 +1,5 @@
import { ForbiddenError } from "@casl/ability";
import { ActionProjectType } from "@app/db/schemas";
import { BadRequestError } from "@app/lib/errors";
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
import { TProjectDALFactory } from "@app/services/project/project-dal";
@@ -36,8 +35,7 @@ export const trustedIpServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.IpAllowList);
const trustedIps = await trustedIpDAL.find({
@@ -61,8 +59,7 @@ export const trustedIpServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.IpAllowList);
@@ -107,8 +104,7 @@ export const trustedIpServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.IpAllowList);
@@ -153,8 +149,7 @@ export const trustedIpServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.IpAllowList);

View File

@@ -2290,9 +2290,6 @@ export const AppConnections = {
accessKey: "The Key used to access Supabase.",
instanceUrl: "The URL used to access Supabase."
},
DIGITAL_OCEAN_APP_PLATFORM: {
apiToken: "The API token used to authenticate with Digital Ocean App Platform."
},
OKTA: {
instanceUrl: "The URL used to access your Okta organization.",
apiToken: "The API token used to authenticate with Okta."
@@ -2509,11 +2506,6 @@ export const SecretSyncs = {
SUPABASE: {
projectId: "The ID of the Supabase project to sync secrets to.",
projectName: "The name of the Supabase project to sync secrets to."
},
BITBUCKET: {
workspaceSlug: "The Bitbucket Workspace slug to sync secrets to.",
repositorySlug: "The Bitbucket Repository slug to sync secrets to.",
environmentId: "The Bitbucket Deployment Environment uuid to sync secrets to."
}
}
};

View File

@@ -260,6 +260,7 @@ import { secretFolderServiceFactory } from "@app/services/secret-folder/secret-f
import { secretFolderVersionDALFactory } from "@app/services/secret-folder/secret-folder-version-dal";
import { secretImportDALFactory } from "@app/services/secret-import/secret-import-dal";
import { secretImportServiceFactory } from "@app/services/secret-import/secret-import-service";
import { secretImportVersionDALFactory } from "@app/services/secret-import/secret-import-version-dal";
import { secretReminderRecipientsDALFactory } from "@app/services/secret-reminder-recipients/secret-reminder-recipients-dal";
import { secretSharingDALFactory } from "@app/services/secret-sharing/secret-sharing-dal";
import { secretSharingServiceFactory } from "@app/services/secret-sharing/secret-sharing-service";
@@ -363,6 +364,7 @@ export const registerRoutes = async (
const folderDAL = secretFolderDALFactory(db);
const folderVersionDAL = secretFolderVersionDALFactory(db);
const secretImportDAL = secretImportDALFactory(db);
const importVersionDAL = secretImportVersionDALFactory(db);
const secretVersionDAL = secretVersionDALFactory(db);
const secretVersionTagDAL = secretVersionTagDALFactory(db);
const secretBlindIndexDAL = secretBlindIndexDALFactory(db);
@@ -622,7 +624,10 @@ export const registerRoutes = async (
userDAL,
identityDAL,
folderDAL,
envDAL: projectEnvDAL,
secretImportDAL,
folderVersionDAL,
importVersionDAL,
secretVersionV2BridgeDAL,
projectDAL,
folderCheckpointResourcesDAL,
@@ -1206,7 +1211,9 @@ export const registerRoutes = async (
secretDAL,
secretQueueService,
secretV2BridgeDAL,
kmsService
kmsService,
importVersionDAL,
folderCommitService
});
const secretBlindIndexService = secretBlindIndexServiceFactory({
permissionService,
@@ -1536,14 +1543,10 @@ export const registerRoutes = async (
folderCommitService,
secretService,
folderService,
secretImportService,
permissionService,
folderDAL,
projectEnvDAL,
secretApprovalRequestService,
secretApprovalPolicyService,
projectDAL,
secretV2BridgeService,
folderCommitDAL
projectEnvDAL
});
const identityOidcAuthService = identityOidcAuthServiceFactory({

View File

@@ -51,10 +51,6 @@ import {
DatabricksConnectionListItemSchema,
SanitizedDatabricksConnectionSchema
} from "@app/services/app-connection/databricks";
import {
DigitalOceanConnectionListItemSchema,
SanitizedDigitalOceanConnectionSchema
} from "@app/services/app-connection/digital-ocean";
import { FlyioConnectionListItemSchema, SanitizedFlyioConnectionSchema } from "@app/services/app-connection/flyio";
import { GcpConnectionListItemSchema, SanitizedGcpConnectionSchema } from "@app/services/app-connection/gcp";
import { GitHubConnectionListItemSchema, SanitizedGitHubConnectionSchema } from "@app/services/app-connection/github";
@@ -144,7 +140,6 @@ const SanitizedAppConnectionSchema = z.union([
...SanitizedRailwayConnectionSchema.options,
...SanitizedChecklyConnectionSchema.options,
...SanitizedSupabaseConnectionSchema.options,
...SanitizedDigitalOceanConnectionSchema.options,
...SanitizedOktaConnectionSchema.options
]);
@@ -183,7 +178,6 @@ const AppConnectionOptionsSchema = z.discriminatedUnion("app", [
RailwayConnectionListItemSchema,
ChecklyConnectionListItemSchema,
SupabaseConnectionListItemSchema,
DigitalOceanConnectionListItemSchema,
OktaConnectionListItemSchema
]);

View File

@@ -85,40 +85,4 @@ export const registerBitbucketConnectionRouter = async (server: FastifyZodProvid
return { repositories };
}
});
server.route({
method: "GET",
url: `/:connectionId/environments`,
config: {
rateLimit: readLimit
},
schema: {
params: z.object({
connectionId: z.string().uuid()
}),
querystring: z.object({
workspaceSlug: z.string().min(1).max(255),
repositorySlug: z.string().min(1).max(255)
}),
response: {
200: z.object({
environments: z.object({ slug: z.string(), name: z.string(), uuid: z.string() }).array()
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const {
params: { connectionId },
query: { workspaceSlug, repositorySlug }
} = req;
const environments = await server.services.appConnection.bitbucket.listEnvironments(
{ connectionId, workspaceSlug, repositorySlug },
req.permission
);
return { environments };
}
});
};

View File

@@ -1,57 +0,0 @@
import { z } from "zod";
import { readLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
import {
CreateDigitalOceanConnectionSchema,
SanitizedDigitalOceanConnectionSchema,
UpdateDigitalOceanConnectionSchema
} from "@app/services/app-connection/digital-ocean";
import { AuthMode } from "@app/services/auth/auth-type";
import { registerAppConnectionEndpoints } from "./app-connection-endpoints";
export const registerDigitalOceanConnectionRouter = async (server: FastifyZodProvider) => {
registerAppConnectionEndpoints({
app: AppConnection.DigitalOcean,
server,
createSchema: CreateDigitalOceanConnectionSchema,
updateSchema: UpdateDigitalOceanConnectionSchema,
sanitizedResponseSchema: SanitizedDigitalOceanConnectionSchema
});
// The below endpoints are not exposed and for Infisical App use
server.route({
method: "GET",
url: `/:connectionId/apps`,
config: {
rateLimit: readLimit
},
schema: {
params: z.object({
connectionId: z.string().uuid()
}),
response: {
200: z.object({
apps: z
.object({
id: z.string(),
spec: z.object({
name: z.string()
})
})
.array()
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const { connectionId } = req.params;
const apps = await server.services.appConnection.digitalOcean.listApps(connectionId, req.permission);
return { apps };
}
});
};

View File

@@ -14,7 +14,6 @@ import { registerCamundaConnectionRouter } from "./camunda-connection-router";
import { registerChecklyConnectionRouter } from "./checkly-connection-router";
import { registerCloudflareConnectionRouter } from "./cloudflare-connection-router";
import { registerDatabricksConnectionRouter } from "./databricks-connection-router";
import { registerDigitalOceanConnectionRouter } from "./digital-ocean-connection-router";
import { registerFlyioConnectionRouter } from "./flyio-connection-router";
import { registerGcpConnectionRouter } from "./gcp-connection-router";
import { registerGitHubConnectionRouter } from "./github-connection-router";
@@ -75,6 +74,5 @@ export const APP_CONNECTION_REGISTER_ROUTER_MAP: Record<AppConnection, (server:
[AppConnection.Railway]: registerRailwayConnectionRouter,
[AppConnection.Checkly]: registerChecklyConnectionRouter,
[AppConnection.Supabase]: registerSupabaseConnectionRouter,
[AppConnection.DigitalOcean]: registerDigitalOceanConnectionRouter,
[AppConnection.Okta]: registerOktaConnectionRouter
};

View File

@@ -158,8 +158,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
includeRoles: z
.enum(["true", "false"])
.default("false")
.transform((value) => value === "true"),
type: z.nativeEnum(ProjectType).optional()
.transform((value) => value === "true")
}),
response: {
200: z.object({
@@ -178,8 +177,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
type: req.query.type
actorOrgId: req.permission.orgId
});
return { workspaces };
}
@@ -1052,7 +1050,6 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
body: z.object({
limit: z.number().default(100),
offset: z.number().default(0),
type: z.nativeEnum(ProjectType).optional(),
orderBy: z.nativeEnum(SearchProjectSortBy).optional().default(SearchProjectSortBy.NAME),
orderDirection: z.nativeEnum(SortDirection).optional().default(SortDirection.ASC),
name: z

View File

@@ -1,17 +0,0 @@
import {
BitbucketSyncSchema,
CreateBitbucketSyncSchema,
UpdateBitbucketSyncSchema
} from "@app/services/secret-sync/bitbucket";
import { SecretSync } from "@app/services/secret-sync/secret-sync-enums";
import { registerSyncSecretsEndpoints } from "./secret-sync-endpoints";
export const registerBitbucketSyncRouter = async (server: FastifyZodProvider) =>
registerSyncSecretsEndpoints({
destination: SecretSync.Bitbucket,
server,
responseSchema: BitbucketSyncSchema,
createSchema: CreateBitbucketSyncSchema,
updateSchema: UpdateBitbucketSyncSchema
});

View File

@@ -1,17 +0,0 @@
import {
CreateDigitalOceanAppPlatformSyncSchema,
DigitalOceanAppPlatformSyncSchema,
UpdateDigitalOceanAppPlatformSyncSchema
} from "@app/services/secret-sync/digital-ocean-app-platform";
import { SecretSync } from "@app/services/secret-sync/secret-sync-enums";
import { registerSyncSecretsEndpoints } from "./secret-sync-endpoints";
export const registerDigitalOceanAppPlatformSyncRouter = async (server: FastifyZodProvider) =>
registerSyncSecretsEndpoints({
destination: SecretSync.DigitalOceanAppPlatform,
server,
responseSchema: DigitalOceanAppPlatformSyncSchema,
createSchema: CreateDigitalOceanAppPlatformSyncSchema,
updateSchema: UpdateDigitalOceanAppPlatformSyncSchema
});

View File

@@ -7,13 +7,11 @@ import { registerAwsSecretsManagerSyncRouter } from "./aws-secrets-manager-sync-
import { registerAzureAppConfigurationSyncRouter } from "./azure-app-configuration-sync-router";
import { registerAzureDevOpsSyncRouter } from "./azure-devops-sync-router";
import { registerAzureKeyVaultSyncRouter } from "./azure-key-vault-sync-router";
import { registerBitbucketSyncRouter } from "./bitbucket-sync-router";
import { registerCamundaSyncRouter } from "./camunda-sync-router";
import { registerChecklySyncRouter } from "./checkly-sync-router";
import { registerCloudflarePagesSyncRouter } from "./cloudflare-pages-sync-router";
import { registerCloudflareWorkersSyncRouter } from "./cloudflare-workers-sync-router";
import { registerDatabricksSyncRouter } from "./databricks-sync-router";
import { registerDigitalOceanAppPlatformSyncRouter } from "./digital-ocean-app-platform-sync-router";
import { registerFlyioSyncRouter } from "./flyio-sync-router";
import { registerGcpSyncRouter } from "./gcp-sync-router";
import { registerGitHubSyncRouter } from "./github-sync-router";
@@ -59,7 +57,5 @@ export const SECRET_SYNC_REGISTER_ROUTER_MAP: Record<SecretSync, (server: Fastif
[SecretSync.Supabase]: registerSupabaseSyncRouter,
[SecretSync.Zabbix]: registerZabbixSyncRouter,
[SecretSync.Railway]: registerRailwaySyncRouter,
[SecretSync.Checkly]: registerChecklySyncRouter,
[SecretSync.DigitalOceanAppPlatform]: registerDigitalOceanAppPlatformSyncRouter,
[SecretSync.Bitbucket]: registerBitbucketSyncRouter
[SecretSync.Checkly]: registerChecklySyncRouter
};

View File

@@ -21,7 +21,6 @@ import {
} from "@app/services/secret-sync/azure-app-configuration";
import { AzureDevOpsSyncListItemSchema, AzureDevOpsSyncSchema } from "@app/services/secret-sync/azure-devops";
import { AzureKeyVaultSyncListItemSchema, AzureKeyVaultSyncSchema } from "@app/services/secret-sync/azure-key-vault";
import { BitbucketSyncListItemSchema, BitbucketSyncSchema } from "@app/services/secret-sync/bitbucket";
import { CamundaSyncListItemSchema, CamundaSyncSchema } from "@app/services/secret-sync/camunda";
import { ChecklySyncListItemSchema, ChecklySyncSchema } from "@app/services/secret-sync/checkly/checkly-sync-schemas";
import {
@@ -33,10 +32,6 @@ import {
CloudflareWorkersSyncSchema
} from "@app/services/secret-sync/cloudflare-workers/cloudflare-workers-schemas";
import { DatabricksSyncListItemSchema, DatabricksSyncSchema } from "@app/services/secret-sync/databricks";
import {
DigitalOceanAppPlatformSyncListItemSchema,
DigitalOceanAppPlatformSyncSchema
} from "@app/services/secret-sync/digital-ocean-app-platform";
import { FlyioSyncListItemSchema, FlyioSyncSchema } from "@app/services/secret-sync/flyio";
import { GcpSyncListItemSchema, GcpSyncSchema } from "@app/services/secret-sync/gcp";
import { GitHubSyncListItemSchema, GitHubSyncSchema } from "@app/services/secret-sync/github";
@@ -80,9 +75,7 @@ const SecretSyncSchema = z.discriminatedUnion("destination", [
SupabaseSyncSchema,
ZabbixSyncSchema,
RailwaySyncSchema,
ChecklySyncSchema,
DigitalOceanAppPlatformSyncSchema,
BitbucketSyncSchema
ChecklySyncSchema
]);
const SecretSyncOptionsSchema = z.discriminatedUnion("destination", [
@@ -109,12 +102,11 @@ const SecretSyncOptionsSchema = z.discriminatedUnion("destination", [
GitLabSyncListItemSchema,
CloudflarePagesSyncListItemSchema,
CloudflareWorkersSyncListItemSchema,
DigitalOceanAppPlatformSyncListItemSchema,
ZabbixSyncListItemSchema,
RailwaySyncListItemSchema,
ChecklySyncListItemSchema,
SupabaseSyncListItemSchema,
BitbucketSyncListItemSchema
SupabaseSyncListItemSchema
]);
export const registerSecretSyncRouter = async (server: FastifyZodProvider) => {

View File

@@ -33,7 +33,6 @@ export enum AppConnection {
Bitbucket = "bitbucket",
Checkly = "checkly",
Supabase = "supabase",
DigitalOcean = "digital-ocean",
Okta = "okta"
}

View File

@@ -68,11 +68,6 @@ import {
getDatabricksConnectionListItem,
validateDatabricksConnectionCredentials
} from "./databricks";
import {
DigitalOceanConnectionMethod,
getDigitalOceanConnectionListItem,
validateDigitalOceanConnectionCredentials
} from "./digital-ocean";
import { FlyioConnectionMethod, getFlyioConnectionListItem, validateFlyioConnectionCredentials } from "./flyio";
import { GcpConnectionMethod, getGcpConnectionListItem, validateGcpConnectionCredentials } from "./gcp";
import { getGitHubConnectionListItem, GitHubConnectionMethod, validateGitHubConnectionCredentials } from "./github";
@@ -162,7 +157,6 @@ export const listAppConnectionOptions = () => {
getBitbucketConnectionListItem(),
getChecklyConnectionListItem(),
getSupabaseConnectionListItem(),
getDigitalOceanConnectionListItem(),
getOktaConnectionListItem()
].sort((a, b) => a.name.localeCompare(b.name));
};
@@ -250,7 +244,6 @@ export const validateAppConnectionCredentials = async (
[AppConnection.Bitbucket]: validateBitbucketConnectionCredentials as TAppConnectionCredentialsValidator,
[AppConnection.Checkly]: validateChecklyConnectionCredentials as TAppConnectionCredentialsValidator,
[AppConnection.Supabase]: validateSupabaseConnectionCredentials as TAppConnectionCredentialsValidator,
[AppConnection.DigitalOcean]: validateDigitalOceanConnectionCredentials as TAppConnectionCredentialsValidator,
[AppConnection.Okta]: validateOktaConnectionCredentials as TAppConnectionCredentialsValidator
};
@@ -290,7 +283,6 @@ export const getAppConnectionMethodName = (method: TAppConnection["method"]) =>
case CloudflareConnectionMethod.APIToken:
case BitbucketConnectionMethod.ApiToken:
case ZabbixConnectionMethod.ApiToken:
case DigitalOceanConnectionMethod.ApiToken:
case OktaConnectionMethod.ApiToken:
return "API Token";
case PostgresConnectionMethod.UsernameAndPassword:
@@ -380,7 +372,6 @@ export const TRANSITION_CONNECTION_CREDENTIALS_TO_PLATFORM: Record<
[AppConnection.Bitbucket]: platformManagedCredentialsNotSupported,
[AppConnection.Checkly]: platformManagedCredentialsNotSupported,
[AppConnection.Supabase]: platformManagedCredentialsNotSupported,
[AppConnection.DigitalOcean]: platformManagedCredentialsNotSupported,
[AppConnection.Okta]: platformManagedCredentialsNotSupported
};

View File

@@ -35,7 +35,6 @@ export const APP_CONNECTION_NAME_MAP: Record<AppConnection, string> = {
[AppConnection.Bitbucket]: "Bitbucket",
[AppConnection.Checkly]: "Checkly",
[AppConnection.Supabase]: "Supabase",
[AppConnection.DigitalOcean]: "DigitalOcean App Platform",
[AppConnection.Okta]: "Okta"
};
@@ -74,6 +73,5 @@ export const APP_CONNECTION_PLAN_MAP: Record<AppConnection, AppConnectionPlanTyp
[AppConnection.Bitbucket]: AppConnectionPlanType.Regular,
[AppConnection.Checkly]: AppConnectionPlanType.Regular,
[AppConnection.Supabase]: AppConnectionPlanType.Regular,
[AppConnection.DigitalOcean]: AppConnectionPlanType.Regular,
[AppConnection.Okta]: AppConnectionPlanType.Regular
};

View File

@@ -61,8 +61,6 @@ import { ValidateCloudflareConnectionCredentialsSchema } from "./cloudflare/clou
import { cloudflareConnectionService } from "./cloudflare/cloudflare-connection-service";
import { ValidateDatabricksConnectionCredentialsSchema } from "./databricks";
import { databricksConnectionService } from "./databricks/databricks-connection-service";
import { ValidateDigitalOceanConnectionCredentialsSchema } from "./digital-ocean";
import { digitalOceanAppPlatformConnectionService } from "./digital-ocean/digital-ocean-connection-service";
import { ValidateFlyioConnectionCredentialsSchema } from "./flyio";
import { flyioConnectionService } from "./flyio/flyio-connection-service";
import { ValidateGcpConnectionCredentialsSchema } from "./gcp";
@@ -147,7 +145,6 @@ const VALIDATE_APP_CONNECTION_CREDENTIALS_MAP: Record<AppConnection, TValidateAp
[AppConnection.Bitbucket]: ValidateBitbucketConnectionCredentialsSchema,
[AppConnection.Checkly]: ValidateChecklyConnectionCredentialsSchema,
[AppConnection.Supabase]: ValidateSupabaseConnectionCredentialsSchema,
[AppConnection.DigitalOcean]: ValidateDigitalOceanConnectionCredentialsSchema,
[AppConnection.Okta]: ValidateOktaConnectionCredentialsSchema
};
@@ -610,7 +607,6 @@ export const appConnectionServiceFactory = ({
bitbucket: bitbucketConnectionService(connectAppConnectionById),
checkly: checklyConnectionService(connectAppConnectionById),
supabase: supabaseConnectionService(connectAppConnectionById),
digitalOcean: digitalOceanAppPlatformConnectionService(connectAppConnectionById),
okta: oktaConnectionService(connectAppConnectionById)
};
};

View File

@@ -87,12 +87,6 @@ import {
TDatabricksConnectionInput,
TValidateDatabricksConnectionCredentialsSchema
} from "./databricks";
import {
TDigitalOceanConnection,
TDigitalOceanConnectionConfig,
TDigitalOceanConnectionInput,
TValidateDigitalOceanCredentialsSchema
} from "./digital-ocean";
import {
TFlyioConnection,
TFlyioConnectionConfig,
@@ -244,7 +238,6 @@ export type TAppConnection = { id: string } & (
| TRailwayConnection
| TChecklyConnection
| TSupabaseConnection
| TDigitalOceanConnection
| TOktaConnection
);
@@ -287,7 +280,6 @@ export type TAppConnectionInput = { id: string } & (
| TRailwayConnectionInput
| TChecklyConnectionInput
| TSupabaseConnectionInput
| TDigitalOceanConnectionInput
| TOktaConnectionInput
);
@@ -338,7 +330,6 @@ export type TAppConnectionConfig =
| TRailwayConnectionConfig
| TChecklyConnectionConfig
| TSupabaseConnectionConfig
| TDigitalOceanConnectionConfig
| TOktaConnectionConfig;
export type TValidateAppConnectionCredentialsSchema =
@@ -376,7 +367,6 @@ export type TValidateAppConnectionCredentialsSchema =
| TValidateRailwayConnectionCredentialsSchema
| TValidateChecklyConnectionCredentialsSchema
| TValidateSupabaseConnectionCredentialsSchema
| TValidateDigitalOceanCredentialsSchema
| TValidateOktaConnectionCredentialsSchema;
export type TListAwsConnectionKmsKeys = {

View File

@@ -9,7 +9,6 @@ import { BitbucketConnectionMethod } from "./bitbucket-connection-enums";
import {
TBitbucketConnection,
TBitbucketConnectionConfig,
TBitbucketEnvironment,
TBitbucketRepo,
TBitbucketWorkspace
} from "./bitbucket-connection-types";
@@ -22,15 +21,11 @@ export const getBitbucketConnectionListItem = () => {
};
};
export const createAuthHeader = (email: string, apiToken: string): string => {
return `Basic ${Buffer.from(`${email}:${apiToken}`).toString("base64")}`;
};
export const getBitbucketUser = async ({ email, apiToken }: { email: string; apiToken: string }) => {
try {
const { data } = await request.get<{ username: string }>(`${IntegrationUrls.BITBUCKET_API_URL}/2.0/user`, {
headers: {
Authorization: createAuthHeader(email, apiToken),
Authorization: `Basic ${Buffer.from(`${email}:${apiToken}`).toString("base64")}`,
Accept: "application/json"
}
});
@@ -62,7 +57,7 @@ export const listBitbucketWorkspaces = async (appConnection: TBitbucketConnectio
const { email, apiToken } = appConnection.credentials;
const headers = {
Authorization: createAuthHeader(email, apiToken),
Authorization: `Basic ${Buffer.from(`${email}:${apiToken}`).toString("base64")}`,
Accept: "application/json"
};
@@ -94,7 +89,7 @@ export const listBitbucketRepositories = async (appConnection: TBitbucketConnect
const { email, apiToken } = appConnection.credentials;
const headers = {
Authorization: createAuthHeader(email, apiToken),
Authorization: `Basic ${Buffer.from(`${email}:${apiToken}`).toString("base64")}`,
Accept: "application/json"
};
@@ -120,43 +115,3 @@ export const listBitbucketRepositories = async (appConnection: TBitbucketConnect
return allRepos;
};
export const listBitbucketEnvironments = async (
appConnection: TBitbucketConnection,
workspaceSlug: string,
repositorySlug: string
) => {
const { email, apiToken } = appConnection.credentials;
const headers = {
Authorization: createAuthHeader(email, apiToken),
Accept: "application/json"
};
const environments: TBitbucketEnvironment[] = [];
let hasNextPage = true;
let environmentsUrl = `${IntegrationUrls.BITBUCKET_API_URL}/2.0/repositories/${encodeURIComponent(workspaceSlug)}/${encodeURIComponent(repositorySlug)}/environments?pagelen=100`;
let iterationCount = 0;
// Limit to 10 iterations, fetching at most 10 * 100 = 1000 environments
while (hasNextPage && iterationCount < 10) {
// eslint-disable-next-line no-await-in-loop
const { data }: { data: { values: TBitbucketEnvironment[]; next: string } } = await request.get(environmentsUrl, {
headers
});
if (data?.values.length > 0) {
environments.push(...data.values);
}
if (data.next) {
environmentsUrl = data.next;
} else {
hasNextPage = false;
}
iterationCount += 1;
}
return environments;
};

View File

@@ -1,16 +1,8 @@
import { OrgServiceActor } from "@app/lib/types";
import { AppConnection } from "../app-connection-enums";
import {
listBitbucketEnvironments,
listBitbucketRepositories,
listBitbucketWorkspaces
} from "./bitbucket-connection-fns";
import {
TBitbucketConnection,
TGetBitbucketEnvironmentsDTO,
TGetBitbucketRepositoriesDTO
} from "./bitbucket-connection-types";
import { listBitbucketRepositories, listBitbucketWorkspaces } from "./bitbucket-connection-fns";
import { TBitbucketConnection, TGetBitbucketRepositoriesDTO } from "./bitbucket-connection-types";
type TGetAppConnectionFunc = (
app: AppConnection,
@@ -34,18 +26,8 @@ export const bitbucketConnectionService = (getAppConnection: TGetAppConnectionFu
return repositories;
};
const listEnvironments = async (
{ connectionId, workspaceSlug, repositorySlug }: TGetBitbucketEnvironmentsDTO,
actor: OrgServiceActor
) => {
const appConnection = await getAppConnection(AppConnection.Bitbucket, connectionId, actor);
const environments = await listBitbucketEnvironments(appConnection, workspaceSlug, repositorySlug);
return environments;
};
return {
listWorkspaces,
listRepositories,
listEnvironments
listRepositories
};
};

View File

@@ -38,20 +38,3 @@ export type TBitbucketRepo = {
full_name: string; // workspace-slug/repo-slug
slug: string;
};
export type TGetBitbucketEnvironmentsDTO = {
connectionId: string;
workspaceSlug: string;
repositorySlug: string;
};
export type TBitbucketEnvironment = {
uuid: string;
slug: string;
name: string;
};
export type TBitbucketEnvironmentsResponse = {
values: TBitbucketEnvironment[];
next?: string;
};

View File

@@ -1,3 +0,0 @@
export enum DigitalOceanConnectionMethod {
ApiToken = "api-token"
}

View File

@@ -1,37 +0,0 @@
/* eslint-disable no-await-in-loop */
import { AxiosError } from "axios";
import { z } from "zod";
import { BadRequestError } from "@app/lib/errors";
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
import { DigitalOceanConnectionMethod } from "./digital-ocean-connection-constants";
import { DigitalOceanAppPlatformPublicAPI } from "./digital-ocean-connection-public-client";
import { DigitalOceanConnectionListItemSchema } from "./digital-ocean-connection-schemas";
import { TDigitalOceanConnectionConfig } from "./digital-ocean-connection-types";
export const getDigitalOceanConnectionListItem = () => {
return {
name: "Digital Ocean" as z.infer<typeof DigitalOceanConnectionListItemSchema>["name"],
app: AppConnection.DigitalOcean as const,
methods: Object.values(DigitalOceanConnectionMethod)
};
};
export const validateDigitalOceanConnectionCredentials = async (config: TDigitalOceanConnectionConfig) => {
try {
await DigitalOceanAppPlatformPublicAPI.healthcheck(config);
} catch (error: unknown) {
if (error instanceof AxiosError) {
throw new BadRequestError({
message: `Failed to validate credentials: ${error.message || "Unknown error"}`
});
}
throw new BadRequestError({
message: "Unable to validate connection - verify credentials"
});
}
return config.credentials;
};

View File

@@ -1,105 +0,0 @@
/* eslint-disable no-await-in-loop */
/* eslint-disable class-methods-use-this */
import { AxiosInstance } from "axios";
import { createRequestClient } from "@app/lib/config/request";
import { IntegrationUrls } from "@app/services/integration-auth/integration-list";
import { DigitalOceanConnectionMethod } from "./digital-ocean-connection-constants";
import {
TDigitalOceanApp,
TDigitalOceanConnectionConfig,
TDigitalOceanVariable
} from "./digital-ocean-connection-types";
class DigitalOceanAppPlatformPublicClient {
private readonly client: AxiosInstance;
constructor() {
this.client = createRequestClient({
baseURL: `${IntegrationUrls.DIGITAL_OCEAN_API_URL}/v2`,
headers: {
"Content-Type": "application/json",
Accept: "application/json"
}
});
}
async healthcheck(connection: TDigitalOceanConnectionConfig) {
switch (connection.method) {
case DigitalOceanConnectionMethod.ApiToken:
await this.getApps(connection);
break;
default:
throw new Error(`Unsupported connection method`);
}
}
async getApps(connection: TDigitalOceanConnectionConfig) {
const response = await this.client.get<{ apps: TDigitalOceanApp[] }>(`/apps`, {
headers: {
Authorization: `Bearer ${connection.credentials.apiToken}`
}
});
return response.data.apps;
}
async getApp(connection: TDigitalOceanConnectionConfig, appId: string) {
const response = await this.client.get<{ app: TDigitalOceanApp }>(`/apps/${appId}`, {
headers: {
Authorization: `Bearer ${connection.credentials.apiToken}`
}
});
return response.data.app;
}
async getVariables(connection: TDigitalOceanConnectionConfig, appId: string): Promise<TDigitalOceanVariable[]> {
const app = await this.getApp(connection, appId);
return app.spec.envs || [];
}
async putVariables(connection: TDigitalOceanConnectionConfig, appId: string, ...input: TDigitalOceanVariable[]) {
const response = await this.getApp(connection, appId);
return this.client.put(
`/apps/${appId}`,
{
spec: {
...response.spec,
envs: input
}
},
{
headers: {
Authorization: `Bearer ${connection.credentials.apiToken}`
}
}
);
}
async deleteVariables(connection: TDigitalOceanConnectionConfig, appId: string, ...input: TDigitalOceanVariable[]) {
const response = await this.getApp(connection, appId);
const existing = response.spec.envs || [];
const variables = existing.filter((v) => input.find((i) => i.key === v.key));
return this.client.put(
`/apps/${appId}`,
{
spec: {
...response.spec,
envs: variables
}
},
{
headers: {
Authorization: `Bearer ${connection.credentials.apiToken}`
}
}
);
}
}
export const DigitalOceanAppPlatformPublicAPI = new DigitalOceanAppPlatformPublicClient();

View File

@@ -1,67 +0,0 @@
import z from "zod";
import { AppConnections } from "@app/lib/api-docs";
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
import {
BaseAppConnectionSchema,
GenericCreateAppConnectionFieldsSchema,
GenericUpdateAppConnectionFieldsSchema
} from "@app/services/app-connection/app-connection-schemas";
import { DigitalOceanConnectionMethod } from "./digital-ocean-connection-constants";
export const DigitalOceanConnectionMethodSchema = z
.nativeEnum(DigitalOceanConnectionMethod)
.describe(AppConnections.CREATE(AppConnection.DigitalOcean).method);
export const DigitalOceanConnectionAccessTokenCredentialsSchema = z.object({
apiToken: z
.string()
.trim()
.min(1, "API Token required")
.max(255)
.describe(AppConnections.CREDENTIALS.DIGITAL_OCEAN_APP_PLATFORM.apiToken)
});
const BaseDigitalOceanConnectionSchema = BaseAppConnectionSchema.extend({
app: z.literal(AppConnection.DigitalOcean)
});
export const DigitalOceanConnectionSchema = BaseDigitalOceanConnectionSchema.extend({
method: DigitalOceanConnectionMethodSchema,
credentials: DigitalOceanConnectionAccessTokenCredentialsSchema
});
export const SanitizedDigitalOceanConnectionSchema = z.discriminatedUnion("method", [
BaseDigitalOceanConnectionSchema.extend({
method: DigitalOceanConnectionMethodSchema,
credentials: DigitalOceanConnectionAccessTokenCredentialsSchema.pick({})
})
]);
export const ValidateDigitalOceanConnectionCredentialsSchema = z.discriminatedUnion("method", [
z.object({
method: DigitalOceanConnectionMethodSchema,
credentials: DigitalOceanConnectionAccessTokenCredentialsSchema.describe(
AppConnections.CREATE(AppConnection.DigitalOcean).credentials
)
})
]);
export const CreateDigitalOceanConnectionSchema = ValidateDigitalOceanConnectionCredentialsSchema.and(
GenericCreateAppConnectionFieldsSchema(AppConnection.DigitalOcean)
);
export const UpdateDigitalOceanConnectionSchema = z
.object({
credentials: DigitalOceanConnectionAccessTokenCredentialsSchema.optional().describe(
AppConnections.UPDATE(AppConnection.DigitalOcean).credentials
)
})
.and(GenericUpdateAppConnectionFieldsSchema(AppConnection.DigitalOcean));
export const DigitalOceanConnectionListItemSchema = z.object({
name: z.literal("Digital Ocean"),
app: z.literal(AppConnection.DigitalOcean),
methods: z.nativeEnum(DigitalOceanConnectionMethod).array()
});

View File

@@ -1,29 +0,0 @@
import { logger } from "@app/lib/logger";
import { OrgServiceActor } from "@app/lib/types";
import { AppConnection } from "../app-connection-enums";
import { DigitalOceanAppPlatformPublicAPI } from "./digital-ocean-connection-public-client";
import { TDigitalOceanConnection } from "./digital-ocean-connection-types";
type TGetAppConnectionFunc = (
app: AppConnection,
connectionId: string,
actor: OrgServiceActor
) => Promise<TDigitalOceanConnection>;
export const digitalOceanAppPlatformConnectionService = (getAppConnection: TGetAppConnectionFunc) => {
const listApps = async (connectionId: string, actor: OrgServiceActor) => {
const connection = await getAppConnection(AppConnection.DigitalOcean, connectionId, actor);
try {
const apps = await DigitalOceanAppPlatformPublicAPI.getApps(connection);
return apps;
} catch (error) {
logger.error(error, "Failed to list apps on Digital Ocean");
return [];
}
};
return {
listApps
};
};

View File

@@ -1,42 +0,0 @@
import z from "zod";
import { DiscriminativePick } from "@app/lib/types";
import { AppConnection } from "../app-connection-enums";
import {
CreateDigitalOceanConnectionSchema,
DigitalOceanConnectionSchema,
ValidateDigitalOceanConnectionCredentialsSchema
} from "./digital-ocean-connection-schemas";
export type TDigitalOceanConnection = z.infer<typeof DigitalOceanConnectionSchema>;
export type TDigitalOceanConnectionInput = z.infer<typeof CreateDigitalOceanConnectionSchema> & {
app: AppConnection.DigitalOcean;
};
export type TValidateDigitalOceanCredentialsSchema = typeof ValidateDigitalOceanConnectionCredentialsSchema;
export type TDigitalOceanConnectionConfig = DiscriminativePick<
TDigitalOceanConnection,
"method" | "app" | "credentials"
> & {
orgId: string;
};
export type TDigitalOceanVariable = {
key: string;
value: string;
type: "SECRET" | "GENERAL";
};
export type TDigitalOceanApp = {
id: string;
spec: {
name: string;
services: Array<{
name: string;
}>;
envs?: TDigitalOceanVariable[];
};
};

View File

@@ -1,4 +0,0 @@
export * from "./digital-ocean-connection-constants";
export * from "./digital-ocean-connection-fns";
export * from "./digital-ocean-connection-schemas";
export * from "./digital-ocean-connection-types";

View File

@@ -1,6 +1,6 @@
import { ForbiddenError } from "@casl/ability";
import { ActionProjectType, TableName } from "@app/db/schemas";
import { TableName } from "@app/db/schemas";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
import { BadRequestError, NotFoundError } from "@app/lib/errors";
@@ -100,8 +100,7 @@ export const certificateAuthorityServiceFactory = ({
actorId: actor.id,
projectId,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId: actor.orgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -168,8 +167,7 @@ export const certificateAuthorityServiceFactory = ({
actorId: actor.id,
projectId: certificateAuthority.projectId,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId: actor.orgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -217,8 +215,7 @@ export const certificateAuthorityServiceFactory = ({
actorId: actor.id,
projectId,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId: actor.orgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -271,8 +268,7 @@ export const certificateAuthorityServiceFactory = ({
actorId: actor.id,
projectId: certificateAuthority.projectId,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId: actor.orgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -345,8 +341,7 @@ export const certificateAuthorityServiceFactory = ({
actorId: actor.id,
projectId: certificateAuthority.projectId,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId: actor.orgId
});
ForbiddenError.from(permission).throwUnlessCan(

View File

@@ -4,7 +4,7 @@ import * as x509 from "@peculiar/x509";
import slugify from "@sindresorhus/slugify";
import { z } from "zod";
import { ActionProjectType, TableName, TCertificateAuthorities, TCertificateTemplates } from "@app/db/schemas";
import { TableName, TCertificateAuthorities, TCertificateTemplates } from "@app/db/schemas";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import {
ProjectPermissionActions,
@@ -150,8 +150,7 @@ export const internalCertificateAuthorityServiceFactory = ({
actorId: dto.actorId,
projectId,
actorAuthMethod: dto.actorAuthMethod,
actorOrgId: dto.actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId: dto.actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -334,8 +333,7 @@ export const internalCertificateAuthorityServiceFactory = ({
actorId,
projectId: ca.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Read,
@@ -359,8 +357,7 @@ export const internalCertificateAuthorityServiceFactory = ({
actorId: dto.actorId,
projectId: ca.projectId,
actorAuthMethod: dto.actorAuthMethod,
actorOrgId: dto.actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId: dto.actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -392,8 +389,7 @@ export const internalCertificateAuthorityServiceFactory = ({
actorId,
projectId: ca.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -418,8 +414,7 @@ export const internalCertificateAuthorityServiceFactory = ({
actorId,
projectId: ca.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -482,8 +477,7 @@ export const internalCertificateAuthorityServiceFactory = ({
actorId,
projectId: ca.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -769,8 +763,7 @@ export const internalCertificateAuthorityServiceFactory = ({
actorId,
projectId: ca.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -806,8 +799,7 @@ export const internalCertificateAuthorityServiceFactory = ({
actorId,
projectId: ca.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -887,8 +879,7 @@ export const internalCertificateAuthorityServiceFactory = ({
actorId,
projectId: ca.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -1035,8 +1026,7 @@ export const internalCertificateAuthorityServiceFactory = ({
actorId,
projectId: ca.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -1207,8 +1197,7 @@ export const internalCertificateAuthorityServiceFactory = ({
actorId,
projectId: ca.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -1564,8 +1553,7 @@ export const internalCertificateAuthorityServiceFactory = ({
actorId: dto.actorId,
projectId: ca.projectId,
actorAuthMethod: dto.actorAuthMethod,
actorOrgId: dto.actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId: dto.actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -1932,8 +1920,7 @@ export const internalCertificateAuthorityServiceFactory = ({
actorId,
projectId: ca.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
const certificateTemplates = await certificateTemplateDAL.find({ caId });

View File

@@ -1,7 +1,7 @@
import { ForbiddenError, subject } from "@casl/ability";
import * as x509 from "@peculiar/x509";
import { ActionProjectType, TCertificateTemplateEstConfigsUpdate } from "@app/db/schemas";
import { TCertificateTemplateEstConfigsUpdate } from "@app/db/schemas";
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import {
@@ -76,8 +76,7 @@ export const certificateTemplateServiceFactory = ({
actorId,
projectId: ca.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -138,8 +137,7 @@ export const certificateTemplateServiceFactory = ({
actorId,
projectId: certTemplate.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -203,8 +201,7 @@ export const certificateTemplateServiceFactory = ({
actorId,
projectId: certTemplate.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -230,8 +227,7 @@ export const certificateTemplateServiceFactory = ({
actorId,
projectId: certTemplate.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -272,8 +268,7 @@ export const certificateTemplateServiceFactory = ({
actorId,
projectId: certTemplate.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -355,8 +350,7 @@ export const certificateTemplateServiceFactory = ({
actorId,
projectId: certTemplate.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -435,8 +429,7 @@ export const certificateTemplateServiceFactory = ({
actorId: dto.actorId,
projectId: certTemplate.projectId,
actorAuthMethod: dto.actorAuthMethod,
actorOrgId: dto.actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId: dto.actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(

View File

@@ -1,7 +1,6 @@
import { ForbiddenError } from "@casl/ability";
import * as x509 from "@peculiar/x509";
import { ActionProjectType } from "@app/db/schemas";
import { TCertificateAuthorityCrlDALFactory } from "@app/ee/services/certificate-authority-crl/certificate-authority-crl-dal";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import {
@@ -80,8 +79,7 @@ export const certificateServiceFactory = ({
actorId,
projectId: cert.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -111,8 +109,7 @@ export const certificateServiceFactory = ({
actorId,
projectId: cert.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -145,8 +142,7 @@ export const certificateServiceFactory = ({
actorId,
projectId: cert.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -195,8 +191,7 @@ export const certificateServiceFactory = ({
actorId,
projectId: ca.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -244,8 +239,7 @@ export const certificateServiceFactory = ({
actorId,
projectId: cert.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -325,8 +319,7 @@ export const certificateServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -530,8 +523,7 @@ export const certificateServiceFactory = ({
actorId,
projectId: cert.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(

View File

@@ -1,6 +1,5 @@
import { ForbiddenError } from "@casl/ability";
import { ActionProjectType } from "@app/db/schemas";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { ProjectPermissionCmekActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
import { SigningAlgorithm } from "@app/lib/crypto/sign";
@@ -39,8 +38,7 @@ export const cmekServiceFactory = ({ kmsService, kmsDAL, permissionService }: TC
actorId: actor.id,
projectId,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.KMS
actorOrgId: actor.orgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionCmekActions.Create, ProjectPermissionSub.Cmek);
@@ -79,8 +77,7 @@ export const cmekServiceFactory = ({ kmsService, kmsDAL, permissionService }: TC
actorId: actor.id,
projectId: key.projectId,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.KMS
actorOrgId: actor.orgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionCmekActions.Edit, ProjectPermissionSub.Cmek);
@@ -116,8 +113,7 @@ export const cmekServiceFactory = ({ kmsService, kmsDAL, permissionService }: TC
actorId: actor.id,
projectId: key.projectId,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.KMS
actorOrgId: actor.orgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionCmekActions.Delete, ProjectPermissionSub.Cmek);
@@ -133,8 +129,7 @@ export const cmekServiceFactory = ({ kmsService, kmsDAL, permissionService }: TC
actorId: actor.id,
projectId,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.KMS
actorOrgId: actor.orgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionCmekActions.Read, ProjectPermissionSub.Cmek);
@@ -156,8 +151,7 @@ export const cmekServiceFactory = ({ kmsService, kmsDAL, permissionService }: TC
actorId: actor.id,
projectId: key.projectId,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.KMS
actorOrgId: actor.orgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionCmekActions.Read, ProjectPermissionSub.Cmek);
@@ -178,8 +172,7 @@ export const cmekServiceFactory = ({ kmsService, kmsDAL, permissionService }: TC
actorId: actor.id,
projectId: key.projectId,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.KMS
actorOrgId: actor.orgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionCmekActions.Read, ProjectPermissionSub.Cmek);
@@ -201,8 +194,7 @@ export const cmekServiceFactory = ({ kmsService, kmsDAL, permissionService }: TC
actorId: actor.id,
projectId: key.projectId,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.KMS
actorOrgId: actor.orgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionCmekActions.Encrypt, ProjectPermissionSub.Cmek);
@@ -229,8 +221,7 @@ export const cmekServiceFactory = ({ kmsService, kmsDAL, permissionService }: TC
actorId: actor.id,
projectId: key.projectId,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.KMS
actorOrgId: actor.orgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionCmekActions.Read, ProjectPermissionSub.Cmek);
@@ -277,8 +268,7 @@ export const cmekServiceFactory = ({ kmsService, kmsDAL, permissionService }: TC
actorId: actor.id,
projectId: key.projectId,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.KMS
actorOrgId: actor.orgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionCmekActions.Read, ProjectPermissionSub.Cmek);
@@ -301,8 +291,7 @@ export const cmekServiceFactory = ({ kmsService, kmsDAL, permissionService }: TC
actorId: actor.id,
projectId: key.projectId,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.KMS
actorOrgId: actor.orgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionCmekActions.Sign, ProjectPermissionSub.Cmek);
@@ -336,8 +325,7 @@ export const cmekServiceFactory = ({ kmsService, kmsDAL, permissionService }: TC
actorId: actor.id,
projectId: key.projectId,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.KMS
actorOrgId: actor.orgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionCmekActions.Verify, ProjectPermissionSub.Cmek);
@@ -372,8 +360,7 @@ export const cmekServiceFactory = ({ kmsService, kmsDAL, permissionService }: TC
actorId: actor.id,
projectId: key.projectId,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.KMS
actorOrgId: actor.orgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionCmekActions.Decrypt, ProjectPermissionSub.Cmek);

View File

@@ -5,7 +5,9 @@ import {
TableName,
TFolderCheckpointResources,
TFolderCheckpoints,
TFolderCommits,
TSecretFolderVersions,
TSecretImportVersions,
TSecretVersionsV2
} from "@app/db/schemas";
import { DatabaseError } from "@app/lib/errors";
@@ -27,10 +29,15 @@ export const folderCheckpointResourcesDALFactory = (db: TDbClient) => {
(TFolderCheckpointResources & {
referencedSecretId?: string;
referencedFolderId?: string;
referencedImportId?: string;
folderName?: string;
folderVersion?: string;
secretKey?: string;
secretVersion?: string;
importPath?: string;
importVersion?: string;
importPosition?: number;
reservedFolderId?: string;
})[]
> => {
try {
@@ -46,19 +53,36 @@ export const folderCheckpointResourcesDALFactory = (db: TDbClient) => {
`${TableName.FolderCheckpointResources}.folderVersionId`,
`${TableName.SecretFolderVersion}.id`
)
.leftJoin<TSecretImportVersions>(
TableName.SecretImportVersion,
`${TableName.FolderCheckpointResources}.importVersionId`,
`${TableName.SecretImportVersion}.id`
)
.leftJoin<TFolderCommits>(
TableName.FolderCommit,
`${TableName.FolderCheckpointResources}.reservedFolderCommitId`,
`${TableName.FolderCommit}.id`
)
.select(selectAllTableCols(TableName.FolderCheckpointResources))
.select(
db.ref("secretId").withSchema(TableName.SecretVersionV2).as("referencedSecretId"),
db.ref("folderId").withSchema(TableName.SecretFolderVersion).as("referencedFolderId"),
db.ref("importId").withSchema(TableName.SecretImportVersion).as("referencedImportId"),
db.ref("name").withSchema(TableName.SecretFolderVersion).as("folderName"),
db.ref("version").withSchema(TableName.SecretFolderVersion).as("folderVersion"),
db.ref("key").withSchema(TableName.SecretVersionV2).as("secretKey"),
db.ref("version").withSchema(TableName.SecretVersionV2).as("secretVersion")
db.ref("version").withSchema(TableName.SecretVersionV2).as("secretVersion"),
db.ref("importPath").withSchema(TableName.SecretImportVersion),
db.ref("version").withSchema(TableName.SecretImportVersion).as("importVersion"),
db.ref("position").withSchema(TableName.SecretImportVersion).as("importPosition"),
db.ref("folderId").withSchema(TableName.FolderCommit).as("reservedFolderId")
);
return docs.map((doc) => ({
...doc,
folderVersion: doc.folderVersion?.toString(),
secretVersion: doc.secretVersion?.toString()
secretVersion: doc.secretVersion?.toString(),
importVersion: doc.importVersion?.toString()
}));
} catch (error) {
throw new DatabaseError({ error, name: "FindByCheckpointId" });

View File

@@ -10,6 +10,7 @@ import {
TSecretFolderVersions,
TSecretVersionsV2
} from "@app/db/schemas";
import { TSecretImportVersions } from "@app/db/schemas/secret-import-versions";
import { DatabaseError } from "@app/lib/errors";
import { buildFindFilter, ormify, selectAllTableCols } from "@app/lib/knex";
@@ -57,8 +58,35 @@ export type FolderCommitChange = BaseCommitChangeInfo & {
}[];
};
// Import-specific change
export type ImportCommitChange = BaseCommitChangeInfo & {
resourceType: "import";
importPosition: number;
importPath: string;
importVersion: string;
importChangeId: string;
versions?: {
version: string;
position: number;
importPath: string;
}[];
};
// Reserved folder-specific change
export type ReservedFolderCommitChange = BaseCommitChangeInfo & {
resourceType: "reserved_folder";
reservedFolderCommitId: string;
versions?: {
reservedFolderCommitId: string;
}[];
};
// Discriminated union
export type CommitChangeWithCommitInfo = SecretCommitChange | FolderCommitChange;
export type CommitChangeWithCommitInfo =
| SecretCommitChange
| FolderCommitChange
| ImportCommitChange
| ReservedFolderCommitChange;
// Type guards
export const isSecretCommitChange = (change: CommitChangeWithCommitInfo): change is SecretCommitChange =>
@@ -67,6 +95,9 @@ export const isSecretCommitChange = (change: CommitChangeWithCommitInfo): change
export const isFolderCommitChange = (change: CommitChangeWithCommitInfo): change is FolderCommitChange =>
change.resourceType === "folder";
export const isImportCommitChange = (change: CommitChangeWithCommitInfo): change is ImportCommitChange =>
change.resourceType === "import";
export const folderCommitChangesDALFactory = (db: TDbClient) => {
const folderCommitChangesOrm = ormify(db, TableName.FolderCommitChanges);
@@ -93,6 +124,11 @@ export const folderCommitChangesDALFactory = (db: TDbClient) => {
`${TableName.FolderCommitChanges}.folderVersionId`,
`${TableName.SecretFolderVersion}.id`
)
.leftJoin<TSecretImportVersions>(
TableName.SecretImportVersion,
`${TableName.FolderCommitChanges}.importVersionId`,
`${TableName.SecretImportVersion}.id`
)
.leftJoin<TProjectEnvironments>(
TableName.Environment,
`${TableName.FolderCommit}.envId`,
@@ -108,6 +144,10 @@ export const folderCommitChangesDALFactory = (db: TDbClient) => {
db.ref("name").withSchema(TableName.SecretFolderVersion).as("folderName"),
db.ref("folderId").withSchema(TableName.SecretFolderVersion).as("folderChangeId"),
db.ref("version").withSchema(TableName.SecretFolderVersion).as("folderVersion"),
db.ref("importId").withSchema(TableName.SecretImportVersion).as("importChangeId"),
db.ref("version").withSchema(TableName.SecretImportVersion).as("importVersion"),
db.ref("position").withSchema(TableName.SecretImportVersion).as("importPosition"),
db.ref("importPath").withSchema(TableName.SecretImportVersion),
db.ref("key").withSchema(TableName.SecretVersionV2).as("secretKey"),
db.ref("version").withSchema(TableName.SecretVersionV2).as("secretVersion"),
db.ref("secretId").withSchema(TableName.SecretVersionV2),
@@ -129,6 +169,23 @@ export const folderCommitChangesDALFactory = (db: TDbClient) => {
secretId: doc.secretId
} as SecretCommitChange;
}
if (doc.importVersion !== null) {
return {
...doc,
resourceType: "import",
importVersion: doc.importVersion.toString(),
importChangeId: doc.importChangeId,
importPosition: doc.importPosition,
importPath: doc.importPath
};
}
if (doc.reservedFolderCommitId != null) {
return {
...doc,
resourceType: "reserved_folder",
reservedFolderCommitId: doc.reservedFolderCommitId
};
}
return {
...doc,
resourceType: "folder",

View File

@@ -7,6 +7,7 @@ import {
TFolderCommits,
TProjectEnvironments,
TSecretFolderVersions,
TSecretImportVersions,
TSecretVersionsV2
} from "@app/db/schemas";
import { DatabaseError, NotFoundError } from "@app/lib/errors";
@@ -197,10 +198,15 @@ export const folderCommitDALFactory = (db: TDbClient) => {
changes: (TFolderCommitChanges & {
referencedSecretId?: string;
referencedFolderId?: string;
referencedImportId?: string;
folderName?: string;
folderVersion?: string;
secretKey?: string;
secretVersion?: string;
importPath?: string;
importVersion?: string;
importPosition?: number;
reservedFolderId?: string;
})[];
})[]
> => {
@@ -235,14 +241,30 @@ export const folderCommitDALFactory = (db: TDbClient) => {
`${TableName.FolderCommitChanges}.folderVersionId`,
`${TableName.SecretFolderVersion}.id`
)
.leftJoin<TSecretImportVersions>(
TableName.SecretImportVersion,
`${TableName.FolderCommitChanges}.importVersionId`,
`${TableName.SecretImportVersion}.id`
)
.leftJoin<TFolderCommits>(
TableName.FolderCommit,
`${TableName.FolderCommitChanges}.reservedFolderCommitId`,
`${TableName.FolderCommit}.id`
)
.select(selectAllTableCols(TableName.FolderCommitChanges))
.select(
db.ref("secretId").withSchema(TableName.SecretVersionV2).as("referencedSecretId"),
db.ref("folderId").withSchema(TableName.SecretFolderVersion).as("referencedFolderId"),
db.ref("importId").withSchema(TableName.SecretImportVersion).as("referencedImportId"),
db.ref("name").withSchema(TableName.SecretFolderVersion).as("folderName"),
db.ref("version").withSchema(TableName.SecretFolderVersion).as("folderVersion"),
db.ref("key").withSchema(TableName.SecretVersionV2).as("secretKey"),
db.ref("version").withSchema(TableName.SecretVersionV2).as("secretVersion")
db.ref("version").withSchema(TableName.SecretVersionV2).as("secretVersion"),
db.ref("importPath").withSchema(TableName.SecretImportVersion),
db.ref("version").withSchema(TableName.SecretImportVersion).as("importVersion"),
db.ref("position").withSchema(TableName.SecretImportVersion).as("importPosition"),
db.ref("position").withSchema(TableName.SecretImportVersion).as("importPosition"),
db.ref("folderId").withSchema(TableName.FolderCommit).as("reservedFolderId")
);
// Organize changes by commit ID

View File

@@ -39,6 +39,13 @@ const folderVersionSchema = z.object({
description: z.string().optional().nullable()
});
// Import-specific versions schema
const importVersionSchema = z.object({
version: z.string().optional(),
position: z.number(),
importPath: z.string()
});
// Secret commit change schema
const secretCommitChangeSchema = baseChangeSchema.extend({
resourceType: z.literal("secret"),
@@ -59,10 +66,22 @@ const folderCommitChangeSchema = baseChangeSchema.extend({
versions: z.array(folderVersionSchema).optional()
});
// Import commit change schema
const importCommitChangeSchema = baseChangeSchema.extend({
resourceType: z.literal("import"),
importVersionId: z.string().optional().nullable(),
importChangeId: z.string(),
importVersion: z.union([z.string(), z.number()]),
importPosition: z.number(),
importPath: z.string(),
versions: z.array(importVersionSchema).optional()
});
// Discriminated union for commit changes
export const commitChangeSchema = z.discriminatedUnion("resourceType", [
secretCommitChangeSchema,
folderCommitChangeSchema
folderCommitChangeSchema,
importCommitChangeSchema
]);
// Commit schema

View File

@@ -3,9 +3,9 @@ import { ForbiddenError } from "@casl/ability";
import { Knex } from "knex";
import {
ActionProjectType,
TSecretFolders,
TSecretFolderVersions,
TSecretImportVersions,
TSecretV2TagJunctionInsert,
TSecretVersionsV2
} from "@app/db/schemas";
@@ -19,16 +19,22 @@ import { logger } from "@app/lib/logger";
import { ActorAuthMethod, ActorType } from "../auth/auth-type";
import { TFolderCheckpointDALFactory } from "../folder-checkpoint/folder-checkpoint-dal";
import { TFolderCheckpointResourcesDALFactory } from "../folder-checkpoint-resources/folder-checkpoint-resources-dal";
import { TFolderCommitChangesDALFactory } from "../folder-commit-changes/folder-commit-changes-dal";
import {
CommitChangeWithCommitInfo,
TFolderCommitChangesDALFactory
} from "../folder-commit-changes/folder-commit-changes-dal";
import { TFolderTreeCheckpointDALFactory } from "../folder-tree-checkpoint/folder-tree-checkpoint-dal";
import { TFolderTreeCheckpointResourcesDALFactory } from "../folder-tree-checkpoint-resources/folder-tree-checkpoint-resources-dal";
import { TIdentityDALFactory } from "../identity/identity-dal";
import { TKmsServiceFactory } from "../kms/kms-service";
import { KmsDataKey } from "../kms/kms-types";
import { TProjectDALFactory } from "../project/project-dal";
import { TProjectEnvDALFactory } from "../project-env/project-env-dal";
import { TResourceMetadataDALFactory } from "../resource-metadata/resource-metadata-dal";
import { TSecretFolderDALFactory } from "../secret-folder/secret-folder-dal";
import { TSecretFolderVersionDALFactory } from "../secret-folder/secret-folder-version-dal";
import { TSecretImportDALFactory } from "../secret-import/secret-import-dal";
import { TSecretImportVersionDALFactory } from "../secret-import/secret-import-version-dal";
import { TSecretTagDALFactory } from "../secret-tag/secret-tag-dal";
import { TSecretV2BridgeDALFactory } from "../secret-v2-bridge/secret-v2-bridge-dal";
import { TSecretVersionV2DALFactory } from "../secret-v2-bridge/secret-version-dal";
@@ -50,17 +56,11 @@ export enum CommitType {
export enum ResourceType {
SECRET = "secret",
FOLDER = "folder"
FOLDER = "folder",
IMPORT = "import",
RESERVED_FOLDER = "reserved_folder"
}
export type TCommitResourceChangeDTO = {
type: string;
secretVersionId?: string;
folderVersionId?: string;
isUpdate?: boolean;
folderId?: string;
};
type TCreateCommitDTO = {
actor: {
type: string;
@@ -71,7 +71,15 @@ type TCreateCommitDTO = {
};
message?: string;
folderId: string;
changes: TCommitResourceChangeDTO[];
changes: {
type: string;
secretVersionId?: string;
folderVersionId?: string;
importVersionId?: string;
reservedFolderCommitId?: string;
isUpdate?: boolean;
folderId?: string;
}[];
omitIgnoreFilter?: boolean;
};
@@ -80,6 +88,8 @@ type TCommitChangeDTO = {
changeType: string;
secretVersionId?: string;
folderVersionId?: string;
importVersionId?: string;
reservedFolderCommitId?: string;
};
type BaseChange = {
@@ -119,6 +129,25 @@ type FolderChange = BaseChange & {
}[];
};
type ImportChange = BaseChange & {
type: ResourceType.IMPORT;
importPath: string;
importVersion: string;
importPosition: number;
versions?: {
position: number;
importPath: string;
}[];
};
type ReservedFolderChange = BaseChange & {
type: ResourceType.RESERVED_FOLDER;
reservedFolderCommitId: string;
versions?: {
reservedFolderCommitId: string;
}[];
};
type SecretTargetChange = {
type: ResourceType.SECRET;
id: string;
@@ -137,7 +166,25 @@ type FolderTargetChange = {
fromVersion?: string;
};
export type ResourceChange = SecretChange | FolderChange;
type ImportTargetChange = {
type: ResourceType.IMPORT;
id: string;
versionId: string;
importPath: string;
importVersion: string;
importPosition: number;
fromVersion?: string;
};
type ReservedFolderTargetChange = {
type: ResourceType.RESERVED_FOLDER;
id: string; // reserved folder ID
versionId: string; // reserved folder commit UUID
reservedFolderCommitId: string; // reserved folder commit UUID
fromVersion?: string;
};
export type ResourceChange = SecretChange | FolderChange | ImportChange | ReservedFolderChange;
type ActorInfo = {
actorType: string;
@@ -148,6 +195,8 @@ type ActorInfo = {
type StateChangeResult = {
secretChangesCount: number;
folderChangesCount: number;
importChangesCount: number;
reservedFolderChangesCount: number;
totalChanges: number;
};
@@ -161,7 +210,10 @@ type TFolderCommitServiceFactoryDep = {
userDAL: TUserDALFactory;
identityDAL: TIdentityDALFactory;
folderDAL: TSecretFolderDALFactory;
envDAL: TProjectEnvDALFactory;
secretImportDAL: TSecretImportDALFactory;
folderVersionDAL: TSecretFolderVersionDALFactory;
importVersionDAL: TSecretImportVersionDALFactory;
secretVersionV2BridgeDAL: TSecretVersionV2DALFactory;
secretV2BridgeDAL: TSecretV2BridgeDALFactory;
projectDAL: Pick<TProjectDALFactory, "findById" | "findProjectByEnvId">;
@@ -191,7 +243,10 @@ export const folderCommitServiceFactory = ({
userDAL,
identityDAL,
folderDAL,
envDAL,
secretImportDAL,
folderVersionDAL,
importVersionDAL,
secretVersionV2BridgeDAL,
projectDAL,
secretV2BridgeDAL,
@@ -225,8 +280,7 @@ export const folderCommitServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionCommitsActions.Read, ProjectPermissionSub.Commits);
@@ -245,7 +299,9 @@ export const folderCommitServiceFactory = ({
resources.push(
...Object.values(folderVersions).map((folderVersion) => ({
folderVersionId: folderVersion.id,
secretVersionId: undefined
secretVersionId: undefined,
importVersionId: undefined,
reservedFolderCommitId: undefined
}))
);
}
@@ -253,7 +309,12 @@ export const folderCommitServiceFactory = ({
const secretVersions = await secretVersionV2BridgeDAL.findLatestVersionByFolderId(folderId, tx);
if (secretVersions.length > 0) {
resources.push(
...secretVersions.map((secretVersion) => ({ secretVersionId: secretVersion.id, folderVersionId: undefined }))
...secretVersions.map((secretVersion) => ({
secretVersionId: secretVersion.id,
folderVersionId: undefined,
importVersionId: undefined,
reservedFolderCommitId: undefined
}))
);
}
@@ -325,7 +386,7 @@ export const folderCommitServiceFactory = ({
const reconstructFolderState = async (
folderCommitId: string,
tx?: Knex
): Promise<(SecretTargetChange | FolderTargetChange)[]> => {
): Promise<(SecretTargetChange | FolderTargetChange | ImportTargetChange | ReservedFolderTargetChange)[]> => {
const targetCommit = await folderCommitDAL.findById(folderCommitId, tx);
if (!targetCommit) {
throw new NotFoundError({ message: `Commit with ID ${folderCommitId} not found` });
@@ -342,7 +403,10 @@ export const folderCommitServiceFactory = ({
const checkpointResources = await folderCheckpointResourcesDAL.findByCheckpointId(nearestCheckpoint.id, tx);
const folderState: Record<string, SecretTargetChange | FolderTargetChange> = {};
const folderState: Record<
string,
SecretTargetChange | FolderTargetChange | ImportTargetChange | ReservedFolderTargetChange
> = {};
// Add all checkpoint resources to initial state
checkpointResources.forEach((resource) => {
@@ -362,6 +426,22 @@ export const folderCommitServiceFactory = ({
folderName: resource.folderName,
folderVersion: resource.folderVersion
} as FolderTargetChange;
} else if (resource.importVersionId && resource.referencedImportId) {
folderState[`import-${resource.referencedImportId}`] = {
type: ResourceType.IMPORT,
id: resource.referencedImportId,
versionId: resource.importVersionId,
importPath: resource.importPath,
importVersion: resource.importVersion,
importPosition: resource.importPosition
} as ImportTargetChange;
} else if (resource.reservedFolderCommitId && resource.reservedFolderId) {
folderState[`reserved-folder-${resource.reservedFolderId}`] = {
type: ResourceType.RESERVED_FOLDER,
id: resource.reservedFolderId,
versionId: resource.reservedFolderCommitId,
reservedFolderCommitId: resource.reservedFolderCommitId
} as ReservedFolderTargetChange;
}
});
@@ -406,6 +486,34 @@ export const folderCommitServiceFactory = ({
} else if (change.changeType.toLowerCase() === "delete") {
delete folderState[key];
}
} else if (change.importVersionId && change.referencedImportId) {
const key = `import-${change.referencedImportId}`;
if (change.changeType.toLowerCase() === "add") {
folderState[key] = {
type: ResourceType.IMPORT,
id: change.referencedImportId,
versionId: change.importVersionId,
importPath: change.importPath,
importVersion: change.importVersion,
importPosition: change.importPosition
} as ImportTargetChange;
} else if (change.changeType.toLowerCase() === "delete") {
delete folderState[key];
}
} else if (change.reservedFolderCommitId && change.reservedFolderId) {
const key = `reserved-folder-${change.reservedFolderId}`;
if (change.changeType.toLowerCase() === "add") {
folderState[key] = {
type: ResourceType.RESERVED_FOLDER,
id: change.reservedFolderId,
versionId: change.reservedFolderCommitId,
reservedFolderCommitId: change.reservedFolderCommitId
} as ReservedFolderTargetChange;
} else if (change.changeType.toLowerCase() === "delete") {
delete folderState[key];
}
}
}
}
@@ -466,6 +574,29 @@ export const folderCommitServiceFactory = ({
folderVersion: resource.folderVersion
};
}
if (resource.type === ResourceType.IMPORT) {
return {
type: ResourceType.IMPORT,
id: resource.id,
versionId: resource.versionId,
changeType: defaultOperation as ChangeType,
commitId: targetCommit.commitId,
importPath: resource.importPath,
importPosition: resource.importPosition,
importVersion: resource.importVersion
};
}
if (resource.type === ResourceType.RESERVED_FOLDER) {
return {
type: ResourceType.RESERVED_FOLDER,
id: resource.id,
versionId: resource.versionId,
changeType: defaultOperation as ChangeType,
commitId: targetCommit.commitId,
reservedFolderCommitId: resource.reservedFolderCommitId
};
}
return null;
})
.filter((change): change is ResourceChange => !!change);
@@ -476,7 +607,10 @@ export const folderCommitServiceFactory = ({
const targetState = await reconstructFolderState(targetCommitId, tx);
// Create lookup maps for easier comparison
const currentMap: Record<string, SecretTargetChange | FolderTargetChange> = {};
const currentMap: Record<
string,
SecretTargetChange | FolderTargetChange | ImportTargetChange | ReservedFolderTargetChange
> = {};
const targetMap: Record<
string,
{
@@ -487,6 +621,9 @@ export const folderCommitServiceFactory = ({
secretVersion?: string;
folderName?: string;
folderVersion?: string;
importPath?: string;
importVersion?: string;
reservedFolderCommitId?: string;
fromVersion?: string;
}
> = {};
@@ -535,12 +672,35 @@ export const folderCommitServiceFactory = ({
folderVersion: currentResource.folderVersion,
fromVersion: currentResource.versionId
});
} else if (currentResource.type === ResourceType.IMPORT) {
differences.push({
type: ResourceType.IMPORT,
id: currentResource.id,
versionId: currentResource.versionId,
changeType: ChangeType.DELETE,
commitId: targetCommit.commitId,
importPath: currentResource.importPath,
importVersion: currentResource.importVersion,
importPosition: currentResource.importPosition,
fromVersion: currentResource.versionId
});
} else if (currentResource.type === ResourceType.RESERVED_FOLDER) {
differences.push({
type: ResourceType.RESERVED_FOLDER,
id: currentResource.id,
versionId: currentResource.versionId,
changeType: ChangeType.DELETE,
commitId: targetCommit.commitId,
reservedFolderCommitId: currentResource.reservedFolderCommitId,
fromVersion: currentResource.versionId
});
}
} else if (currentResource.versionId !== targetResource.versionId) {
// Resource was updated
if (targetResource.type === ResourceType.SECRET) {
const secretCurrentResource = currentResource as SecretTargetChange;
const secretTargetResource = targetResource as SecretTargetChange;
differences.push({
type: ResourceType.SECRET,
id: secretTargetResource.id,
@@ -566,6 +726,34 @@ export const folderCommitServiceFactory = ({
folderVersion: folderTargetResource.folderVersion,
fromVersion: folderCurrentResource.folderVersion
});
} else if (targetResource.type === ResourceType.IMPORT) {
const importCurrentResource = currentResource as ImportTargetChange;
const importTargetResource = targetResource as ImportTargetChange;
differences.push({
type: ResourceType.IMPORT,
id: importTargetResource.id,
versionId: importTargetResource.versionId,
changeType: ChangeType.UPDATE,
commitId: targetCommit.commitId,
importPath: importTargetResource.importPath,
importVersion: importTargetResource.importVersion,
importPosition: importTargetResource.importPosition,
fromVersion: importCurrentResource.importVersion
});
} else if (targetResource.type === ResourceType.RESERVED_FOLDER) {
const rfCurrentResource = currentResource as ReservedFolderTargetChange;
const rfTargetResource = targetResource as ReservedFolderTargetChange;
differences.push({
type: ResourceType.RESERVED_FOLDER,
id: rfTargetResource.id,
versionId: rfTargetResource.versionId,
changeType: ChangeType.UPDATE,
commitId: targetCommit.commitId,
reservedFolderCommitId: rfTargetResource.reservedFolderCommitId,
fromVersion: rfCurrentResource.reservedFolderCommitId
});
}
}
});
@@ -599,6 +787,30 @@ export const folderCommitServiceFactory = ({
folderName: folderTargetResource.folderName,
folderVersion: folderTargetResource.folderVersion
});
} else if (targetResource.type === ResourceType.IMPORT) {
const importTargetResource = targetResource as ImportTargetChange;
differences.push({
type: ResourceType.IMPORT,
id: importTargetResource.id,
versionId: importTargetResource.versionId,
changeType: ChangeType.CREATE,
commitId: targetCommit.commitId,
createdAt: targetCommit.createdAt,
importPath: importTargetResource.importPath,
importVersion: importTargetResource.importVersion,
importPosition: importTargetResource.importPosition
});
} else if (targetResource.type === ResourceType.RESERVED_FOLDER) {
const rfTargetResource = targetResource as ReservedFolderTargetChange;
differences.push({
type: ResourceType.RESERVED_FOLDER,
id: rfTargetResource.id,
versionId: rfTargetResource.versionId,
changeType: ChangeType.CREATE,
commitId: targetCommit.commitId,
createdAt: targetCommit.createdAt,
reservedFolderCommitId: rfTargetResource.reservedFolderCommitId
});
}
}
});
@@ -666,6 +878,40 @@ export const folderCommitServiceFactory = ({
if (uniqueVersions.length === 1) {
removeNoChangeUpdate.push(change.id);
}
} else if (change.type === ResourceType.IMPORT && change.importVersion && change.fromVersion) {
const versions = await importVersionDAL.find({
importId: change.id,
$in: {
version: [Number(change.importVersion), Number(change.fromVersion)]
}
});
const versionsShaped = versions.map((version) => ({
position: version.position,
importPath: version.importPath
}));
const uniqueVersions = versionsShaped.filter(
(item, index, arr) =>
arr.findIndex((other) =>
Object.entries(item).every(
([key, value]) => JSON.stringify(value) === JSON.stringify(other[key as keyof typeof other])
)
) === index
);
if (uniqueVersions.length === 1) {
removeNoChangeUpdate.push(change.id);
}
} else if (
change.type === ResourceType.RESERVED_FOLDER &&
change.reservedFolderCommitId &&
change.fromVersion
) {
const res = await compareFolderStates({
targetCommitId: change.reservedFolderCommitId,
currentCommitId: change.fromVersion,
tx
});
removeNoChangeUpdate.concat(res.map((v) => v.id));
}
}
})
@@ -873,7 +1119,7 @@ export const folderCommitServiceFactory = ({
*/
const createCommit = async (data: TCreateCommitDTO, tx?: Knex) => {
try {
const metadata = { ...data.actor.metadata } || {};
const metadata = { ...data.actor.metadata };
if (data.actor.type === ActorType.USER && data.actor.metadata?.id) {
const user = await userDAL.findById(data.actor.metadata?.id, tx);
@@ -926,6 +1172,8 @@ export const folderCommitServiceFactory = ({
changeType: change.type,
secretVersionId: change.secretVersionId,
folderVersionId: change.folderVersionId,
importVersionId: change.importVersionId,
reservedFolderCommitId: change.reservedFolderCommitId,
isUpdate: change.isUpdate || false
})),
tx
@@ -1339,6 +1587,280 @@ export const folderCommitServiceFactory = ({
return commitChanges;
};
/**
* Process import changes when applying import state differences
*/
const processImportChanges = async (
changes: ResourceChange[],
importVersions: Record<string, TSecretImportVersions>
) => {
const commitChanges = [];
const importChanges = changes.filter(
(change): change is ResourceChange & ImportChange => change.type === ResourceType.IMPORT
);
for (const change of importChanges) {
const importVersion = importVersions[change.id];
switch (change.changeType) {
case "create":
if (importVersion) {
const lastPos = await secretImportDAL.findLastImportPosition(folderId, tx);
await secretImportDAL.updateAllPosition(folderId, lastPos + 1, importVersion.position, 1, tx);
const newImport = {
id: change.id,
folderId,
version: (importVersion.version || 1) + 1,
position: importVersion.position,
importEnv: importVersion.importEnv,
importPath: importVersion.importPath,
isReplication: importVersion.isReplication,
isReserved: importVersion.isReserved
};
await secretImportDAL.create(newImport, tx);
const newImportVersion = await importVersionDAL.create(
{
importId: change.id,
version: (importVersion.version || 1) + 1,
position: importVersion.position,
importEnv: importVersion.importEnv,
importPath: importVersion.importPath,
isReplication: importVersion.isReplication,
isReserved: importVersion.isReserved
},
tx
);
commitChanges.push({
type: ChangeType.ADD,
importVersionId: newImportVersion.id
});
}
break;
case "update":
if (change.versionId) {
const latestVersionDetails = await importVersionDAL.findByIdsWithLatestVersion(
[change.id],
[change.versionId],
tx
);
if (latestVersionDetails && Object.keys(latestVersionDetails).length > 0) {
const versionDetails = Object.values(latestVersionDetails)[0];
await secretImportDAL.updateById(
change.id,
{
version: (versionDetails.version || 1) + 1,
position: versionDetails.position,
importPath: versionDetails.importPath // This should never change
},
tx
);
const newImportVersion = await importVersionDAL.create(
{
importId: change.id,
version: (versionDetails.version || 1) + 1,
position: versionDetails.position,
importEnv: versionDetails.importEnv,
importPath: versionDetails.importPath,
isReplication: versionDetails.isReplication,
isReserved: versionDetails.isReserved
},
tx
);
commitChanges.push({
type: ChangeType.ADD,
isUpdate: true,
importVersionId: newImportVersion.id
});
const updatedImports = await secretImportDAL.updateAllPosition(
folderId,
change.importPosition,
newImportVersion.position,
1,
tx
);
for (const updatedImport of updatedImports) {
// eslint-disable-next-line no-await-in-loop
const importVersionNested = await importVersionDAL.create(
{
importId: updatedImport.id,
position: updatedImport.position,
importEnv: updatedImport.importEnv,
importPath: updatedImport.importPath,
isReplication: updatedImport.isReplication,
isReserved: updatedImport.isReserved,
version: updatedImport.version
},
tx
);
commitChanges.push({
type: ChangeType.ADD,
isUpdate: true,
importVersionId: importVersionNested.id
});
}
}
}
break;
case "delete": {
const doc = await secretImportDAL.deleteById(change.id, tx);
commitChanges.push({
type: ChangeType.DELETE,
importVersionId: change.versionId,
importId: change.id
});
await secretImportDAL.updateAllPosition(folderId, doc.position, -1, 1, tx);
break;
}
default:
throw new BadRequestError({ message: `Unknown change type: ${change.changeType}` });
}
}
return commitChanges;
};
/**
* Process reserved folder changes when applying reserved folder state differences
*/
const processReservedFolderChanges = async (changes: ResourceChange[]) => {
// TODO(andrey): This was implemented wrong and actually needs to push the changes to the GHOST folder, creating a commit on there
// Then point to that commit using a new commit on the parent FOLDER
//
// We're putting the issue on hold so I'm not going to waste time adding this for now
const commitChanges = [];
const reservedFolderChanges = changes.filter(
(change): change is ResourceChange & ReservedFolderChange => change.type === ResourceType.RESERVED_FOLDER
);
for (const change of reservedFolderChanges) {
const ghostFolderId = change.id;
let diff: ResourceChange[] = [];
if (change.changeType === "create") {
diff = await compareFolderStates({
currentCommitId: undefined,
targetCommitId: change.reservedFolderCommitId,
tx
});
commitChanges.push({
type: ChangeType.ADD,
isUpdate: true,
reservedFolderCommitId: change.reservedFolderCommitId
});
} else if (change.changeType === "update") {
if (!change.fromVersion) {
throw new BadRequestError({
message: "Reserved folder previous version (fromVersion) is required for update"
});
}
diff = await compareFolderStates({
currentCommitId: change.fromVersion,
targetCommitId: change.reservedFolderCommitId,
tx
});
commitChanges.push({
type: ChangeType.ADD,
isUpdate: true,
reservedFolderCommitId: change.reservedFolderCommitId
});
} else if (change.changeType === "delete") {
if (!change.fromVersion) {
throw new BadRequestError({
message: "Reserved folder previous version (fromVersion) is required for delete"
});
}
const currentGhostFolderStateContents = await reconstructFolderState(change.fromVersion, tx);
diff = currentGhostFolderStateContents
.map((resource) => {
const baseChange: ResourceChange = {
type: resource.type,
id: resource.id,
versionId: resource.versionId,
changeType: ChangeType.DELETE,
commitId: BigInt(0),
fromVersion: resource.versionId
} as ResourceChange;
switch (resource.type) {
case ResourceType.SECRET:
return {
...baseChange,
secretKey: resource.secretKey,
secretVersion: resource.secretVersion,
secretId: resource.id
} as ResourceChange;
case ResourceType.FOLDER:
return {
...baseChange,
folderName: resource.folderName,
folderVersion: resource.folderVersion
} as ResourceChange;
case ResourceType.IMPORT:
return {
...baseChange,
importPath: resource.importPath,
importVersion: resource.importVersion,
importPosition: resource.importPosition
} as ResourceChange;
case ResourceType.RESERVED_FOLDER:
return {
...baseChange,
reservedFolderCommitId: resource.reservedFolderCommitId
} as ResourceChange;
default:
return null;
}
})
.filter((c): c is ResourceChange => c !== null);
commitChanges.push({
type: ChangeType.ADD,
isUpdate: true,
reservedFolderCommitId: change.reservedFolderCommitId,
id: ghostFolderId
});
} else {
throw new BadRequestError({ message: `Unknown change type for reserved folder: ${change.changeType}` });
}
if (diff.length > 0) {
await applyFolderStateDifferencesFn({
differences: diff,
actorInfo,
folderId: ghostFolderId,
projectId,
reconstructNewFolders: true,
reconstructUpToCommit: change.reservedFolderCommitId,
step: step + 1,
tx
});
}
}
return commitChanges;
};
// Group differences by type for more efficient processing using discriminated unions
const secretChanges = differences.filter(
(diff): diff is ResourceChange & SecretChange => diff.type === ResourceType.SECRET
@@ -1346,6 +1868,12 @@ export const folderCommitServiceFactory = ({
const folderChanges = differences.filter(
(diff): diff is ResourceChange & FolderChange => diff.type === ResourceType.FOLDER
);
const importChanges = differences.filter(
(diff): diff is ResourceChange & ImportChange => diff.type === ResourceType.IMPORT
);
const reservedFolderChanges = differences.filter(
(diff): diff is ResourceChange & ReservedFolderChange => diff.type === ResourceType.RESERVED_FOLDER
);
// Batch fetch necessary data
const secretVersions = await secretVersionV2BridgeDAL.findByIdsWithLatestVersion(
@@ -1361,14 +1889,28 @@ export const folderCommitServiceFactory = ({
tx
);
const importVersions = await importVersionDAL.findByIdsWithLatestVersion(
importChanges.map((diff) => diff.id),
importChanges.map((diff) => diff.versionId),
tx
);
// Process changes in parallel
const [secretCommitChanges, folderCommitChanges] = await Promise.all([
processSecretChanges(differences, secretVersions, actorInfo, folderId, tx),
processFolderChanges(differences, folderVersions)
]);
const [secretCommitChanges, folderCommitChanges, importCommitChanges, reservedFolderCommitChanges] =
await Promise.all([
processSecretChanges(differences, secretVersions, actorInfo, folderId, tx),
processFolderChanges(differences, folderVersions),
processImportChanges(differences, importVersions),
processReservedFolderChanges(differences)
]);
// Combine all changes
const allCommitChanges = [...secretCommitChanges, ...folderCommitChanges];
const allCommitChanges = [
...secretCommitChanges,
...folderCommitChanges,
...importCommitChanges,
...reservedFolderCommitChanges
];
// Create a commit with all the changes
await createCommit(
@@ -1391,6 +1933,8 @@ export const folderCommitServiceFactory = ({
return {
secretChangesCount: secretChanges.length,
folderChangesCount: folderChanges.length,
importChangesCount: importChanges.length,
reservedFolderChangesCount: reservedFolderChanges.length,
totalChanges: differences.length
};
};
@@ -1561,9 +2105,24 @@ export const folderCommitServiceFactory = ({
projectId
});
const changes = await folderCommitChangesDAL.findByCommitId(commitId, projectId);
const updatedChanges: CommitChangeWithCommitInfo[] = [];
for (const change of changes) {
if (change.reservedFolderCommitId) {
const nestedChanges = await folderCommitChangesDAL.findByCommitId(change.reservedFolderCommitId, projectId);
for (const nestedChange of nestedChanges) {
updatedChanges.push(nestedChange);
}
} else {
updatedChanges.push(change);
}
}
const commit = await folderCommitDAL.findById(commitId, undefined, projectId);
const latestCommit = await folderCommitDAL.findLatestCommit(commit.folderId, projectId);
return { ...commit, changes, isLatest: commit.id === latestCommit?.id };
return { ...commit, changes: updatedChanges, isLatest: commit.id === latestCommit?.id };
};
/**
@@ -1601,6 +2160,8 @@ export const folderCommitServiceFactory = ({
changeType: change.type,
secretVersionId: change.secretVersionId,
folderVersionId: change.folderVersionId,
importVersionId: change.importVersionId,
reservedFolderCommitId: change.reservedFolderCommitId,
isUpdate: false
}))
};
@@ -2069,8 +2630,7 @@ export const folderCommitServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(

View File

@@ -1,6 +1,6 @@
import { ForbiddenError } from "@casl/ability";
import { ActionProjectType, ProjectMembershipRole, SecretKeyEncoding, TGroups } from "@app/db/schemas";
import { ProjectMembershipRole, SecretKeyEncoding, TGroups } from "@app/db/schemas";
import { TListProjectGroupUsersDTO } from "@app/ee/services/group/group-types";
import {
constructPermissionErrorMessage,
@@ -78,8 +78,7 @@ export const groupProjectServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionGroupActions.Create, ProjectPermissionSub.Groups);
@@ -272,8 +271,7 @@ export const groupProjectServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionGroupActions.Edit, ProjectPermissionSub.Groups);
@@ -386,8 +384,7 @@ export const groupProjectServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionGroupActions.Delete, ProjectPermissionSub.Groups);
@@ -431,8 +428,7 @@ export const groupProjectServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionGroupActions.Read, ProjectPermissionSub.Groups);
@@ -459,8 +455,7 @@ export const groupProjectServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionGroupActions.Read, ProjectPermissionSub.Groups);
@@ -501,8 +496,7 @@ export const groupProjectServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionGroupActions.Read, ProjectPermissionSub.Groups);

View File

@@ -1,6 +1,6 @@
import { ForbiddenError, subject } from "@casl/ability";
import { ActionProjectType, ProjectMembershipRole } from "@app/db/schemas";
import { ProjectMembershipRole } from "@app/db/schemas";
import {
constructPermissionErrorMessage,
validatePrivilegeChangeOperation
@@ -62,8 +62,7 @@ export const identityProjectServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionIdentityActions.Create,
@@ -182,8 +181,7 @@ export const identityProjectServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionIdentityActions.Edit,
@@ -293,8 +291,7 @@ export const identityProjectServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionIdentityActions.Delete,
@@ -322,8 +319,7 @@ export const identityProjectServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionIdentityActions.Read,
@@ -356,8 +352,7 @@ export const identityProjectServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -393,8 +388,7 @@ export const identityProjectServiceFactory = ({
actorId,
projectId: membership.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(

View File

@@ -4,13 +4,7 @@ import { Octokit } from "@octokit/rest";
import { Client as OctopusClient, SpaceRepository as OctopusSpaceRepository } from "@octopusdeploy/api-client";
import AWS from "aws-sdk";
import {
ActionProjectType,
SecretEncryptionAlgo,
SecretKeyEncoding,
TIntegrationAuths,
TIntegrationAuthsInsert
} from "@app/db/schemas";
import { SecretEncryptionAlgo, SecretKeyEncoding, TIntegrationAuths, TIntegrationAuthsInsert } from "@app/db/schemas";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
import { getConfig } from "@app/lib/config/env";
@@ -103,8 +97,7 @@ export const integrationAuthServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const authorizations = await integrationAuthDAL.find({ projectId });
@@ -122,8 +115,7 @@ export const integrationAuthServiceFactory = ({
actorId,
projectId: auth.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
return permission.can(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations) ? auth : null;
@@ -146,8 +138,7 @@ export const integrationAuthServiceFactory = ({
actorId,
projectId: integrationAuth.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
return integrationAuth;
@@ -172,8 +163,7 @@ export const integrationAuthServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.Integrations);
@@ -291,8 +281,7 @@ export const integrationAuthServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.Integrations);
@@ -446,8 +435,7 @@ export const integrationAuthServiceFactory = ({
actorId,
projectId: integrationAuth.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Integrations);
@@ -744,8 +732,7 @@ export const integrationAuthServiceFactory = ({
actorId,
projectId: integrationAuth.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
@@ -779,8 +766,7 @@ export const integrationAuthServiceFactory = ({
actorId,
projectId: integrationAuth.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
@@ -810,8 +796,7 @@ export const integrationAuthServiceFactory = ({
actorId,
projectId: integrationAuth.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const { shouldUseSecretV2Bridge, botKey } = await projectBotService.getBotKey(integrationAuth.projectId);
@@ -852,8 +837,7 @@ export const integrationAuthServiceFactory = ({
actorId,
projectId: integrationAuth.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const { shouldUseSecretV2Bridge, botKey } = await projectBotService.getBotKey(integrationAuth.projectId);
@@ -881,8 +865,7 @@ export const integrationAuthServiceFactory = ({
actorId,
projectId: integrationAuth.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const { shouldUseSecretV2Bridge, botKey } = await projectBotService.getBotKey(integrationAuth.projectId);
@@ -956,8 +939,7 @@ export const integrationAuthServiceFactory = ({
actorId,
projectId: integrationAuth.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const { shouldUseSecretV2Bridge, botKey } = await projectBotService.getBotKey(integrationAuth.projectId);
@@ -1004,8 +986,7 @@ export const integrationAuthServiceFactory = ({
actorId,
projectId: integrationAuth.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const { shouldUseSecretV2Bridge, botKey } = await projectBotService.getBotKey(integrationAuth.projectId);
@@ -1039,8 +1020,7 @@ export const integrationAuthServiceFactory = ({
actorId,
projectId: integrationAuth.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const { shouldUseSecretV2Bridge, botKey } = await projectBotService.getBotKey(integrationAuth.projectId);
@@ -1098,8 +1078,7 @@ export const integrationAuthServiceFactory = ({
actorId,
projectId: integrationAuth.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const { shouldUseSecretV2Bridge, botKey } = await projectBotService.getBotKey(integrationAuth.projectId);
@@ -1135,8 +1114,7 @@ export const integrationAuthServiceFactory = ({
actorId,
projectId: integrationAuth.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const { shouldUseSecretV2Bridge, botKey } = await projectBotService.getBotKey(integrationAuth.projectId);
@@ -1177,8 +1155,7 @@ export const integrationAuthServiceFactory = ({
actorId,
projectId: integrationAuth.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const { shouldUseSecretV2Bridge, botKey } = await projectBotService.getBotKey(integrationAuth.projectId);
@@ -1218,8 +1195,7 @@ export const integrationAuthServiceFactory = ({
actorId,
projectId: integrationAuth.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const { shouldUseSecretV2Bridge, botKey } = await projectBotService.getBotKey(integrationAuth.projectId);
@@ -1259,8 +1235,7 @@ export const integrationAuthServiceFactory = ({
actorId,
projectId: integrationAuth.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const { shouldUseSecretV2Bridge, botKey } = await projectBotService.getBotKey(integrationAuth.projectId);
@@ -1299,8 +1274,7 @@ export const integrationAuthServiceFactory = ({
actorId,
projectId: integrationAuth.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const { shouldUseSecretV2Bridge, botKey } = await projectBotService.getBotKey(integrationAuth.projectId);
@@ -1340,8 +1314,7 @@ export const integrationAuthServiceFactory = ({
actorId,
projectId: integrationAuth.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const { shouldUseSecretV2Bridge, botKey } = await projectBotService.getBotKey(integrationAuth.projectId);
@@ -1409,8 +1382,7 @@ export const integrationAuthServiceFactory = ({
actorId,
projectId: integrationAuth.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const { shouldUseSecretV2Bridge, botKey } = await projectBotService.getBotKey(integrationAuth.projectId);
@@ -1484,8 +1456,7 @@ export const integrationAuthServiceFactory = ({
actorId,
projectId: integrationAuth.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const { shouldUseSecretV2Bridge, botKey } = await projectBotService.getBotKey(integrationAuth.projectId);
@@ -1535,8 +1506,7 @@ export const integrationAuthServiceFactory = ({
actorId,
projectId: integrationAuth.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const { shouldUseSecretV2Bridge, botKey } = await projectBotService.getBotKey(integrationAuth.projectId);
@@ -1584,8 +1554,7 @@ export const integrationAuthServiceFactory = ({
actorId,
projectId: integrationAuth.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const { shouldUseSecretV2Bridge, botKey } = await projectBotService.getBotKey(integrationAuth.projectId);
@@ -1653,8 +1622,7 @@ export const integrationAuthServiceFactory = ({
actorId,
projectId: integrationAuth.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const { shouldUseSecretV2Bridge, botKey } = await projectBotService.getBotKey(integrationAuth.projectId);
@@ -1695,8 +1663,7 @@ export const integrationAuthServiceFactory = ({
actorId,
projectId: integrationAuth.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const { shouldUseSecretV2Bridge, botKey } = await projectBotService.getBotKey(integrationAuth.projectId);
@@ -1808,8 +1775,7 @@ export const integrationAuthServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Delete, ProjectPermissionSub.Integrations);
@@ -1832,8 +1798,7 @@ export const integrationAuthServiceFactory = ({
actorId,
projectId: integrationAuth.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Delete, ProjectPermissionSub.Integrations);
@@ -1866,8 +1831,7 @@ export const integrationAuthServiceFactory = ({
actorId,
projectId: integrationAuth.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(sourcePermission).throwUnlessCan(
@@ -1880,8 +1844,7 @@ export const integrationAuthServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(targetPermission).throwUnlessCan(
@@ -1914,8 +1877,7 @@ export const integrationAuthServiceFactory = ({
actorId,
projectId: integrationAuth.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
@@ -1949,8 +1911,7 @@ export const integrationAuthServiceFactory = ({
actorId,
projectId: integrationAuth.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const { shouldUseSecretV2Bridge, botKey } = await projectBotService.getBotKey(integrationAuth.projectId);
@@ -1990,8 +1951,7 @@ export const integrationAuthServiceFactory = ({
actorId,
projectId: integrationAuth.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const { shouldUseSecretV2Bridge, botKey } = await projectBotService.getBotKey(integrationAuth.projectId);

View File

@@ -1,6 +1,5 @@
import { ForbiddenError } from "@casl/ability";
import { ActionProjectType } from "@app/db/schemas";
import { throwIfMissingSecretReadValueOrDescribePermission } from "@app/ee/services/permission/permission-fns";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import {
@@ -91,8 +90,7 @@ export const integrationServiceFactory = ({
actorId,
projectId: integrationAuth.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.Integrations);
@@ -167,8 +165,7 @@ export const integrationServiceFactory = ({
actorId,
projectId: integration.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Integrations);
@@ -231,8 +228,7 @@ export const integrationServiceFactory = ({
actorId,
projectId: integration.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
@@ -259,8 +255,7 @@ export const integrationServiceFactory = ({
actorId,
projectId: integration.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
@@ -302,8 +297,7 @@ export const integrationServiceFactory = ({
actorId,
projectId: integration.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Delete, ProjectPermissionSub.Integrations);
@@ -339,8 +333,7 @@ export const integrationServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
@@ -359,8 +352,7 @@ export const integrationServiceFactory = ({
actorId,
projectId: integration.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);

View File

@@ -3,7 +3,6 @@ import slugify from "@sindresorhus/slugify";
import { Knex } from "knex";
import {
ActionProjectType,
OrgMembershipRole,
OrgMembershipStatus,
ProjectMembershipRole,
@@ -981,8 +980,7 @@ export const orgServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(projectPermission).throwUnlessCan(
ProjectPermissionMemberActions.Create,

View File

@@ -1,6 +1,5 @@
import { ForbiddenError } from "@casl/ability";
import { ActionProjectType } from "@app/db/schemas";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
import { ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
@@ -79,8 +78,7 @@ export const pkiAlertServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.PkiAlerts);
@@ -109,8 +107,7 @@ export const pkiAlertServiceFactory = ({
actorId,
projectId: alert.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.PkiAlerts);
@@ -136,8 +133,7 @@ export const pkiAlertServiceFactory = ({
actorId,
projectId: alert.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.PkiAlerts);
@@ -169,8 +165,7 @@ export const pkiAlertServiceFactory = ({
actorId,
projectId: alert.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Delete, ProjectPermissionSub.PkiAlerts);

View File

@@ -1,6 +1,6 @@
import { ForbiddenError } from "@casl/ability";
import { ActionProjectType, TPkiCollectionItems } from "@app/db/schemas";
import { TPkiCollectionItems } from "@app/db/schemas";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
import { BadRequestError, NotFoundError } from "@app/lib/errors";
@@ -55,8 +55,7 @@ export const pkiCollectionServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -88,8 +87,7 @@ export const pkiCollectionServiceFactory = ({
actorId,
projectId: pkiCollection.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.PkiCollections);
@@ -113,8 +111,7 @@ export const pkiCollectionServiceFactory = ({
actorId,
projectId: pkiCollection.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.PkiCollections);
@@ -141,8 +138,7 @@ export const pkiCollectionServiceFactory = ({
actorId,
projectId: pkiCollection.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -171,8 +167,7 @@ export const pkiCollectionServiceFactory = ({
actorId,
projectId: pkiCollection.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.PkiCollections);
@@ -215,8 +210,7 @@ export const pkiCollectionServiceFactory = ({
actorId,
projectId: pkiCollection.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -303,8 +297,7 @@ export const pkiCollectionServiceFactory = ({
actorId,
projectId: pkiCollection.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(

View File

@@ -2,7 +2,6 @@
import { ForbiddenError, subject } from "@casl/ability";
import * as x509 from "@peculiar/x509";
import { ActionProjectType } from "@app/db/schemas";
import { TCertificateAuthorityCrlDALFactory } from "@app/ee/services/certificate-authority-crl/certificate-authority-crl-dal";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import {
@@ -120,8 +119,7 @@ export const pkiSubscriberServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -183,8 +181,7 @@ export const pkiSubscriberServiceFactory = ({
actorId,
projectId: subscriber.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -237,8 +234,7 @@ export const pkiSubscriberServiceFactory = ({
actorId,
projectId: subscriber.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -300,8 +296,7 @@ export const pkiSubscriberServiceFactory = ({
actorId,
projectId: subscriber.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -337,8 +332,7 @@ export const pkiSubscriberServiceFactory = ({
actorId,
projectId: subscriber.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -393,8 +387,7 @@ export const pkiSubscriberServiceFactory = ({
actorId,
projectId: subscriber.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -440,8 +433,7 @@ export const pkiSubscriberServiceFactory = ({
actorId,
projectId: ca.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -699,8 +691,7 @@ export const pkiSubscriberServiceFactory = ({
actorId,
projectId: subscriber.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -747,8 +738,7 @@ export const pkiSubscriberServiceFactory = ({
actorId,
projectId: subscriber.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(

View File

@@ -3,7 +3,6 @@ import { ForbiddenError, subject } from "@casl/ability";
import * as x509 from "@peculiar/x509";
import RE2 from "re2";
import { ActionProjectType } from "@app/db/schemas";
import { TCertificateAuthorityCrlDALFactory } from "@app/ee/services/certificate-authority-crl/certificate-authority-crl-dal";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import {
@@ -119,8 +118,7 @@ export const pkiTemplatesServiceFactory = ({
actorId,
projectId: ca.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -172,8 +170,7 @@ export const pkiTemplatesServiceFactory = ({
actorId,
projectId: certTemplate.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -236,8 +233,7 @@ export const pkiTemplatesServiceFactory = ({
actorId,
projectId: certTemplate.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -269,8 +265,7 @@ export const pkiTemplatesServiceFactory = ({
actorId,
projectId: certTemplate.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -295,8 +290,7 @@ export const pkiTemplatesServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
const certTemplate = await pkiTemplatesDAL.find({ projectId }, { limit, offset, count: true });
@@ -338,8 +332,7 @@ export const pkiTemplatesServiceFactory = ({
actorId,
projectId: certTemplate.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -385,8 +378,7 @@ export const pkiTemplatesServiceFactory = ({
actorId,
projectId: certTemplate.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(

View File

@@ -1,6 +1,6 @@
import { ForbiddenError } from "@casl/ability";
import { ActionProjectType, ProjectVersion } from "@app/db/schemas";
import { ProjectVersion } from "@app/db/schemas";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
import { crypto } from "@app/lib/crypto/cryptography";
@@ -45,8 +45,7 @@ export const projectBotServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
@@ -116,8 +115,7 @@ export const projectBotServiceFactory = ({
actorId,
projectId: bot.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Integrations);

View File

@@ -1,6 +1,5 @@
import { ForbiddenError } from "@casl/ability";
import { ActionProjectType } from "@app/db/schemas";
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
@@ -47,8 +46,7 @@ export const projectEnvServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.Environments);
@@ -136,8 +134,7 @@ export const projectEnvServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Environments);
@@ -200,8 +197,7 @@ export const projectEnvServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Delete, ProjectPermissionSub.Environments);
@@ -256,8 +252,7 @@ export const projectEnvServiceFactory = ({
actorId,
projectId: environment.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.SecretManager
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Environments);

View File

@@ -1,6 +1,5 @@
import { ForbiddenError } from "@casl/ability";
import { ActionProjectType } from "@app/db/schemas";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { ProjectPermissionMemberActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
import { BadRequestError } from "@app/lib/errors";
@@ -37,8 +36,7 @@ export const projectKeyServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionMemberActions.Edit, ProjectPermissionSub.Member);
@@ -67,8 +65,7 @@ export const projectKeyServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
const latestKey = await projectKeyDAL.findLatestProjectKey(actorId, projectId);
return latestKey;
@@ -86,8 +83,7 @@ export const projectKeyServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionMemberActions.Read, ProjectPermissionSub.Member);
return projectKeyDAL.findAllProjectUserPubKeys(projectId);

View File

@@ -1,7 +1,7 @@
/* eslint-disable no-await-in-loop */
import { ForbiddenError } from "@casl/ability";
import { ActionProjectType, ProjectMembershipRole, ProjectVersion, TableName } from "@app/db/schemas";
import { ProjectMembershipRole, ProjectVersion, TableName } from "@app/db/schemas";
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
import {
constructPermissionErrorMessage,
@@ -90,8 +90,7 @@ export const projectMembershipServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionMemberActions.Read, ProjectPermissionSub.Member);
@@ -134,8 +133,7 @@ export const projectMembershipServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionMemberActions.Read, ProjectPermissionSub.Member);
@@ -157,8 +155,7 @@ export const projectMembershipServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionMemberActions.Read, ProjectPermissionSub.Member);
@@ -184,8 +181,7 @@ export const projectMembershipServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionMemberActions.Create, ProjectPermissionSub.Member);
const orgMembers = await orgDAL.findMembership({
@@ -265,8 +261,7 @@ export const projectMembershipServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionMemberActions.Edit, ProjectPermissionSub.Member);
@@ -375,8 +370,7 @@ export const projectMembershipServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionMemberActions.Delete, ProjectPermissionSub.Member);
@@ -418,8 +412,7 @@ export const projectMembershipServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionMemberActions.Delete, ProjectPermissionSub.Member);

View File

@@ -11,7 +11,7 @@ import {
} from "@app/ee/services/permission/default-roles";
import { TGetPredefinedRolesDTO } from "@app/services/project-role/project-role-types";
export const getPredefinedRoles = ({ projectId, projectType, roleFilter }: TGetPredefinedRolesDTO) => {
export const getPredefinedRoles = ({ projectId, roleFilter }: TGetPredefinedRolesDTO) => {
return [
{
id: uuidv4(),
@@ -75,5 +75,5 @@ export const getPredefinedRoles = ({ projectId, projectType, roleFilter }: TGetP
createdAt: new Date(),
updatedAt: new Date()
}
].filter(({ slug, type }) => (type ? type === projectType : true) && (!roleFilter || roleFilter === slug));
].filter(({ slug }) => !roleFilter || roleFilter === slug);
};

View File

@@ -2,7 +2,7 @@ import { ForbiddenError, MongoAbility, RawRuleOf } from "@casl/ability";
import { PackRule, packRules, unpackRules } from "@casl/ability/extra";
import { requestContext } from "@fastify/request-context";
import { ActionProjectType, ProjectMembershipRole, ProjectType, TableName, TProjects } from "@app/db/schemas";
import { ProjectMembershipRole, TableName, TProjects } from "@app/db/schemas";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import {
ProjectPermissionActions,
@@ -71,8 +71,7 @@ export const projectRoleServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.Role);
const existingRole = await projectRoleDAL.findOne({ slug: data.slug, projectId });
@@ -112,14 +111,12 @@ export const projectRoleServiceFactory = ({
actorId,
projectId: project.id,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Role);
if (roleSlug !== "custom" && Object.values(ProjectMembershipRole).includes(roleSlug as ProjectMembershipRole)) {
const [predefinedRole] = getPredefinedRoles({
projectId: project.id,
projectType: project.type as ProjectType,
roleFilter: roleSlug as ProjectMembershipRole
});
@@ -142,8 +139,7 @@ export const projectRoleServiceFactory = ({
actorId,
projectId: projectRole.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Role);
@@ -173,8 +169,7 @@ export const projectRoleServiceFactory = ({
actorId,
projectId: projectRole.projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Delete, ProjectPermissionSub.Role);
@@ -215,18 +210,14 @@ export const projectRoleServiceFactory = ({
actorId,
projectId: project.id,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Role);
const customRoles = await projectRoleDAL.find(
{ projectId: project.id },
{ sort: [[`${TableName.ProjectRoles}.slug` as "slug", "asc"]] }
);
const roles = [
...getPredefinedRoles({ projectId: project.id, projectType: project.type as ProjectType }),
...(customRoles || [])
];
const roles = [...getPredefinedRoles({ projectId: project.id }), ...(customRoles || [])];
return roles;
};
@@ -242,8 +233,7 @@ export const projectRoleServiceFactory = ({
actorId: userId,
projectId,
actorAuthMethod,
actorOrgId,
actionProjectType: ActionProjectType.Any
actorOrgId
});
// just to satisfy ts
if (!("roles" in membership)) throw new BadRequestError({ message: "Service token not allowed" });

View File

@@ -1,4 +1,4 @@
import { ProjectMembershipRole, ProjectType, TOrgRolesUpdate, TProjectRolesInsert } from "@app/db/schemas";
import { ProjectMembershipRole, TOrgRolesUpdate, TProjectRolesInsert } from "@app/db/schemas";
import { TProjectPermission } from "@app/lib/types";
export enum ProjectRoleServiceIdentifierType {
@@ -37,6 +37,5 @@ export type TListRolesDTO = {
export type TGetPredefinedRolesDTO = {
projectId: string;
projectType: ProjectType;
roleFilter?: ProjectMembershipRole;
};

Some files were not shown because too many files have changed in this diff Show More