Merge branch 'main' into feature/north-flank-app-connection

This commit is contained in:
Victor Santos
2025-10-23 12:46:55 -03:00
282 changed files with 7525 additions and 2865 deletions
@@ -1,6 +1,6 @@
import { ForbiddenError, subject } from "@casl/ability";
import { ActionProjectType, TAppConnections } from "@app/db/schemas";
import { ActionProjectType, OrganizationActionScope, TAppConnections } from "@app/db/schemas";
import { ValidateOCIConnectionCredentialsSchema } from "@app/ee/services/app-connections/oci";
import { ociConnectionService } from "@app/ee/services/app-connections/oci/oci-connection-service";
import { ValidateOracleDBConnectionCredentialsSchema } from "@app/ee/services/app-connections/oracledb";
@@ -218,13 +218,14 @@ export const appConnectionServiceFactory = ({
)
);
} else {
const { permission } = await permissionService.getOrgPermission(
actor.type,
actor.id,
actor.orgId,
actor.authMethod,
actor.orgId
);
const { permission } = await permissionService.getOrgPermission({
actorId: actor.id,
actor: actor.type,
orgId: actor.orgId,
actorOrgId: actor.orgId,
actorAuthMethod: actor.authMethod,
scope: OrganizationActionScope.Any
});
ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionAppConnectionActions.Read,
@@ -271,13 +272,14 @@ export const appConnectionServiceFactory = ({
subject(ProjectPermissionSub.AppConnections, { connectionId })
);
} else {
const { permission } = await permissionService.getOrgPermission(
actor.type,
actor.id,
appConnection.orgId,
actor.authMethod,
actor.orgId
);
const { permission } = await permissionService.getOrgPermission({
actorId: actor.id,
actor: actor.type,
orgId: appConnection.orgId,
actorOrgId: actor.orgId,
actorAuthMethod: actor.authMethod,
scope: OrganizationActionScope.Any
});
ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionAppConnectionActions.Read,
@@ -321,13 +323,14 @@ export const appConnectionServiceFactory = ({
subject(ProjectPermissionSub.AppConnections, { connectionId: appConnection.id })
);
} else {
const { permission } = await permissionService.getOrgPermission(
actor.type,
actor.id,
appConnection.orgId,
actor.authMethod,
actor.orgId
);
const { permission } = await permissionService.getOrgPermission({
actorId: actor.id,
actor: actor.type,
orgId: appConnection.orgId,
actorOrgId: actor.orgId,
actorAuthMethod: actor.authMethod,
scope: OrganizationActionScope.Any
});
ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionAppConnectionActions.Read,
@@ -345,13 +348,14 @@ export const appConnectionServiceFactory = ({
{ method, app, credentials, gatewayId, projectId, ...params }: TCreateAppConnectionDTO,
actor: OrgServiceActor
) => {
const { permission: orgPermission } = await permissionService.getOrgPermission(
actor.type,
actor.id,
actor.orgId,
actor.authMethod,
actor.orgId
);
const { permission: orgPermission } = await permissionService.getOrgPermission({
actorId: actor.id,
actor: actor.type,
orgId: actor.orgId,
actorOrgId: actor.orgId,
actorAuthMethod: actor.authMethod,
scope: OrganizationActionScope.Any
});
if (projectId) {
const project = await projectDAL.findProjectById(projectId);
@@ -480,13 +484,14 @@ export const appConnectionServiceFactory = ({
"Failed to update app connection due to plan restriction. Upgrade plan to access enterprise app connections."
);
const { permission: orgPermission } = await permissionService.getOrgPermission(
actor.type,
actor.id,
appConnection.orgId,
actor.authMethod,
actor.orgId
);
const { permission: orgPermission } = await permissionService.getOrgPermission({
actorId: actor.id,
actor: actor.type,
orgId: appConnection.orgId,
actorOrgId: actor.orgId,
actorAuthMethod: actor.authMethod,
scope: OrganizationActionScope.Any
});
if (appConnection.projectId) {
const { permission } = await permissionService.getProjectPermission({
@@ -638,13 +643,14 @@ export const appConnectionServiceFactory = ({
subject(ProjectPermissionSub.AppConnections, { connectionId })
);
} else {
const { permission } = await permissionService.getOrgPermission(
actor.type,
actor.id,
appConnection.orgId,
actor.authMethod,
actor.orgId
);
const { permission } = await permissionService.getOrgPermission({
actorId: actor.id,
actor: actor.type,
orgId: appConnection.orgId,
actorOrgId: actor.orgId,
actorAuthMethod: actor.authMethod,
scope: OrganizationActionScope.Any
});
ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionAppConnectionActions.Delete,
@@ -707,13 +713,14 @@ export const appConnectionServiceFactory = ({
subject(ProjectPermissionSub.AppConnections, { connectionId })
);
} else {
const { permission: orgPermission } = await permissionService.getOrgPermission(
actor.type,
actor.id,
appConnection.orgId,
actor.authMethod,
actor.orgId
);
const { permission: orgPermission } = await permissionService.getOrgPermission({
actorId: actor.id,
actor: actor.type,
orgId: appConnection.orgId,
actorOrgId: actor.orgId,
actorAuthMethod: actor.authMethod,
scope: OrganizationActionScope.Any
});
ForbiddenError.from(orgPermission).throwUnlessCan(
OrgPermissionAppConnectionActions.Connect,
@@ -750,13 +757,14 @@ export const appConnectionServiceFactory = ({
};
const listAvailableAppConnectionsForUser = async (app: AppConnection, actor: OrgServiceActor, projectId?: string) => {
const { permission: orgPermission } = await permissionService.getOrgPermission(
actor.type,
actor.id,
actor.orgId,
actor.authMethod,
actor.orgId
);
const { permission: orgPermission } = await permissionService.getOrgPermission({
actorId: actor.id,
actor: actor.type,
orgId: actor.orgId,
actorOrgId: actor.orgId,
actorAuthMethod: actor.authMethod,
scope: OrganizationActionScope.Any
});
let availableProjectConnections: TAppConnections[] = [];
@@ -808,13 +816,14 @@ export const appConnectionServiceFactory = ({
if (!appConnection) throw new NotFoundError({ message: `Could not find App Connection with ID ${connectionId}` });
const { permission } = await permissionService.getOrgPermission(
actor.type,
actor.id,
appConnection.orgId,
actor.authMethod,
actor.orgId
);
const { permission } = await permissionService.getOrgPermission({
actorId: actor.id,
actor: actor.type,
orgId: appConnection.orgId,
actorOrgId: actor.orgId,
actorAuthMethod: actor.authMethod,
scope: OrganizationActionScope.Any
});
ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionAppConnectionActions.Read,
@@ -25,6 +25,23 @@ import {
THCVaultMountResponse
} from "./hc-vault-connection-types";
// HashiCorp Vault stores JSON data, so values can be any valid JSON type
type JsonValue = string | number | boolean | null | JsonValue[] | { [key: string]: JsonValue };
export const convertVaultValueToString = (value: JsonValue): string => {
if (value === null) {
return "";
}
if (typeof value === "string") {
return value;
}
if (typeof value === "number" || typeof value === "boolean") {
return String(value);
}
// For objects and arrays, serialize as JSON
return JSON.stringify(value);
};
// Concurrency limit for HC Vault API requests to avoid rate limiting
const HC_VAULT_CONCURRENCY_LIMIT = 20;
@@ -598,7 +615,7 @@ export const getHCVaultSecretsForPath = async (
// For KV v2: /v1/{mount}/data/{path}
const { data } = await requestWithHCVaultGateway<{
data: {
data: Record<string, string>; // KV v2 has nested data structure
data: Record<string, JsonValue>; // KV v2 has nested data structure, supports all JSON types
metadata: {
created_time: string;
deletion_time: string;
@@ -620,7 +637,7 @@ export const getHCVaultSecretsForPath = async (
// For KV v1: /v1/{mount}/{path}
const { data } = await requestWithHCVaultGateway<{
data: Record<string, string>; // KV v1 has flat data structure
data: Record<string, JsonValue>; // KV v1 has flat data structure, supports all JSON types
lease_duration: number;
lease_id: string;
renewable: boolean;