mirror of
https://github.com/Infisical/infisical.git
synced 2025-07-15 09:42:14 +00:00
Compare commits
16 Commits
server-adm
...
move-sso-s
Author | SHA1 | Date | |
---|---|---|---|
1aa9be203e | |||
e35ac599f8 | |||
6d91297ca9 | |||
db369b8f51 | |||
a50a95ad6e | |||
4ec0031c42 | |||
a6edb67f58 | |||
aae5831f35 | |||
6f78a6b4c1 | |||
c2e326b95a | |||
97c96acea5 | |||
5e24015f2a | |||
f17e1f6699 | |||
e71b136859 | |||
7d2d69fc7d | |||
0569c7e692 |
@ -0,0 +1,55 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
const existingSecretApprovalPolicies = await knex(TableName.SecretApprovalPolicy)
|
||||||
|
.whereNull("secretPath")
|
||||||
|
.orWhere("secretPath", "");
|
||||||
|
|
||||||
|
const existingAccessApprovalPolicies = await knex(TableName.AccessApprovalPolicy)
|
||||||
|
.whereNull("secretPath")
|
||||||
|
.orWhere("secretPath", "");
|
||||||
|
|
||||||
|
// update all the secret approval policies secretPath to be "/**"
|
||||||
|
if (existingSecretApprovalPolicies.length) {
|
||||||
|
await knex(TableName.SecretApprovalPolicy)
|
||||||
|
.whereIn(
|
||||||
|
"id",
|
||||||
|
existingSecretApprovalPolicies.map((el) => el.id)
|
||||||
|
)
|
||||||
|
.update({
|
||||||
|
secretPath: "/**"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// update all the access approval policies secretPath to be "/**"
|
||||||
|
if (existingAccessApprovalPolicies.length) {
|
||||||
|
await knex(TableName.AccessApprovalPolicy)
|
||||||
|
.whereIn(
|
||||||
|
"id",
|
||||||
|
existingAccessApprovalPolicies.map((el) => el.id)
|
||||||
|
)
|
||||||
|
.update({
|
||||||
|
secretPath: "/**"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await knex.schema.alterTable(TableName.SecretApprovalPolicy, (table) => {
|
||||||
|
table.string("secretPath").notNullable().alter();
|
||||||
|
});
|
||||||
|
|
||||||
|
await knex.schema.alterTable(TableName.AccessApprovalPolicy, (table) => {
|
||||||
|
table.string("secretPath").notNullable().alter();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.alterTable(TableName.SecretApprovalPolicy, (table) => {
|
||||||
|
table.string("secretPath").nullable().alter();
|
||||||
|
});
|
||||||
|
|
||||||
|
await knex.schema.alterTable(TableName.AccessApprovalPolicy, (table) => {
|
||||||
|
table.string("secretPath").nullable().alter();
|
||||||
|
});
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "@app/db/schemas";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
const hasCommitterCol = await knex.schema.hasColumn(TableName.SecretApprovalRequest, "committerUserId");
|
||||||
|
|
||||||
|
if (hasCommitterCol) {
|
||||||
|
await knex.schema.alterTable(TableName.SecretApprovalRequest, (tb) => {
|
||||||
|
tb.uuid("committerUserId").nullable().alter();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasRequesterCol = await knex.schema.hasColumn(TableName.AccessApprovalRequest, "requestedByUserId");
|
||||||
|
|
||||||
|
if (hasRequesterCol) {
|
||||||
|
await knex.schema.alterTable(TableName.AccessApprovalRequest, (tb) => {
|
||||||
|
tb.dropForeign("requestedByUserId");
|
||||||
|
tb.foreign("requestedByUserId").references("id").inTable(TableName.Users).onDelete("CASCADE");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
// can't undo committer nullable
|
||||||
|
|
||||||
|
const hasRequesterCol = await knex.schema.hasColumn(TableName.AccessApprovalRequest, "requestedByUserId");
|
||||||
|
|
||||||
|
if (hasRequesterCol) {
|
||||||
|
await knex.schema.alterTable(TableName.AccessApprovalRequest, (tb) => {
|
||||||
|
tb.dropForeign("requestedByUserId");
|
||||||
|
tb.foreign("requestedByUserId").references("id").inTable(TableName.Users).onDelete("SET NULL");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -14,8 +14,8 @@ export const AccessApprovalPoliciesApproversSchema = z.object({
|
|||||||
updatedAt: z.date(),
|
updatedAt: z.date(),
|
||||||
approverUserId: z.string().uuid().nullable().optional(),
|
approverUserId: z.string().uuid().nullable().optional(),
|
||||||
approverGroupId: z.string().uuid().nullable().optional(),
|
approverGroupId: z.string().uuid().nullable().optional(),
|
||||||
sequence: z.number().default(0).nullable().optional(),
|
sequence: z.number().default(1).nullable().optional(),
|
||||||
approvalsRequired: z.number().default(1).nullable().optional()
|
approvalsRequired: z.number().nullable().optional()
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TAccessApprovalPoliciesApprovers = z.infer<typeof AccessApprovalPoliciesApproversSchema>;
|
export type TAccessApprovalPoliciesApprovers = z.infer<typeof AccessApprovalPoliciesApproversSchema>;
|
||||||
|
@ -11,7 +11,7 @@ export const AccessApprovalPoliciesSchema = z.object({
|
|||||||
id: z.string().uuid(),
|
id: z.string().uuid(),
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
approvals: z.number().default(1),
|
approvals: z.number().default(1),
|
||||||
secretPath: z.string().nullable().optional(),
|
secretPath: z.string(),
|
||||||
envId: z.string().uuid(),
|
envId: z.string().uuid(),
|
||||||
createdAt: z.date(),
|
createdAt: z.date(),
|
||||||
updatedAt: z.date(),
|
updatedAt: z.date(),
|
||||||
|
@ -12,8 +12,8 @@ export const CertificateAuthoritiesSchema = z.object({
|
|||||||
createdAt: z.date(),
|
createdAt: z.date(),
|
||||||
updatedAt: z.date(),
|
updatedAt: z.date(),
|
||||||
projectId: z.string(),
|
projectId: z.string(),
|
||||||
enableDirectIssuance: z.boolean().default(true),
|
|
||||||
status: z.string(),
|
status: z.string(),
|
||||||
|
enableDirectIssuance: z.boolean().default(true),
|
||||||
name: z.string()
|
name: z.string()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -25,8 +25,8 @@ export const CertificatesSchema = z.object({
|
|||||||
certificateTemplateId: z.string().uuid().nullable().optional(),
|
certificateTemplateId: z.string().uuid().nullable().optional(),
|
||||||
keyUsages: z.string().array().nullable().optional(),
|
keyUsages: z.string().array().nullable().optional(),
|
||||||
extendedKeyUsages: z.string().array().nullable().optional(),
|
extendedKeyUsages: z.string().array().nullable().optional(),
|
||||||
pkiSubscriberId: z.string().uuid().nullable().optional(),
|
projectId: z.string(),
|
||||||
projectId: z.string()
|
pkiSubscriberId: z.string().uuid().nullable().optional()
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TCertificates = z.infer<typeof CertificatesSchema>;
|
export type TCertificates = z.infer<typeof CertificatesSchema>;
|
||||||
|
@ -10,7 +10,7 @@ import { TImmutableDBKeys } from "./models";
|
|||||||
export const SecretApprovalPoliciesSchema = z.object({
|
export const SecretApprovalPoliciesSchema = z.object({
|
||||||
id: z.string().uuid(),
|
id: z.string().uuid(),
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
secretPath: z.string().nullable().optional(),
|
secretPath: z.string(),
|
||||||
approvals: z.number().default(1),
|
approvals: z.number().default(1),
|
||||||
envId: z.string().uuid(),
|
envId: z.string().uuid(),
|
||||||
createdAt: z.date(),
|
createdAt: z.date(),
|
||||||
|
@ -18,7 +18,7 @@ export const SecretApprovalRequestsSchema = z.object({
|
|||||||
createdAt: z.date(),
|
createdAt: z.date(),
|
||||||
updatedAt: z.date(),
|
updatedAt: z.date(),
|
||||||
isReplicated: z.boolean().nullable().optional(),
|
isReplicated: z.boolean().nullable().optional(),
|
||||||
committerUserId: z.string().uuid(),
|
committerUserId: z.string().uuid().nullable().optional(),
|
||||||
statusChangedByUserId: z.string().uuid().nullable().optional(),
|
statusChangedByUserId: z.string().uuid().nullable().optional(),
|
||||||
bypassReason: z.string().nullable().optional()
|
bypassReason: z.string().nullable().optional()
|
||||||
});
|
});
|
||||||
|
@ -2,6 +2,7 @@ import { nanoid } from "nanoid";
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { ApproverType, BypasserType } from "@app/ee/services/access-approval-policy/access-approval-policy-types";
|
import { ApproverType, BypasserType } from "@app/ee/services/access-approval-policy/access-approval-policy-types";
|
||||||
|
import { removeTrailingSlash } from "@app/lib/fn";
|
||||||
import { EnforcementLevel } from "@app/lib/types";
|
import { EnforcementLevel } from "@app/lib/types";
|
||||||
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
@ -19,7 +20,7 @@ export const registerAccessApprovalPolicyRouter = async (server: FastifyZodProvi
|
|||||||
body: z.object({
|
body: z.object({
|
||||||
projectSlug: z.string().trim(),
|
projectSlug: z.string().trim(),
|
||||||
name: z.string().optional(),
|
name: z.string().optional(),
|
||||||
secretPath: z.string().trim().default("/"),
|
secretPath: z.string().trim().min(1, { message: "Secret path cannot be empty" }).transform(removeTrailingSlash),
|
||||||
environment: z.string(),
|
environment: z.string(),
|
||||||
approvers: z
|
approvers: z
|
||||||
.discriminatedUnion("type", [
|
.discriminatedUnion("type", [
|
||||||
@ -174,8 +175,9 @@ export const registerAccessApprovalPolicyRouter = async (server: FastifyZodProvi
|
|||||||
secretPath: z
|
secretPath: z
|
||||||
.string()
|
.string()
|
||||||
.trim()
|
.trim()
|
||||||
|
.min(1, { message: "Secret path cannot be empty" })
|
||||||
.optional()
|
.optional()
|
||||||
.transform((val) => (val === "" ? "/" : val)),
|
.transform((val) => (val ? removeTrailingSlash(val) : val)),
|
||||||
approvers: z
|
approvers: z
|
||||||
.discriminatedUnion("type", [
|
.discriminatedUnion("type", [
|
||||||
z.object({
|
z.object({
|
||||||
|
@ -23,10 +23,8 @@ export const registerSecretApprovalPolicyRouter = async (server: FastifyZodProvi
|
|||||||
environment: z.string(),
|
environment: z.string(),
|
||||||
secretPath: z
|
secretPath: z
|
||||||
.string()
|
.string()
|
||||||
.optional()
|
.min(1, { message: "Secret path cannot be empty" })
|
||||||
.nullable()
|
.transform((val) => removeTrailingSlash(val)),
|
||||||
.default("/")
|
|
||||||
.transform((val) => (val ? removeTrailingSlash(val) : val)),
|
|
||||||
approvers: z
|
approvers: z
|
||||||
.discriminatedUnion("type", [
|
.discriminatedUnion("type", [
|
||||||
z.object({ type: z.literal(ApproverType.Group), id: z.string() }),
|
z.object({ type: z.literal(ApproverType.Group), id: z.string() }),
|
||||||
@ -100,10 +98,10 @@ export const registerSecretApprovalPolicyRouter = async (server: FastifyZodProvi
|
|||||||
approvals: z.number().min(1).default(1),
|
approvals: z.number().min(1).default(1),
|
||||||
secretPath: z
|
secretPath: z
|
||||||
.string()
|
.string()
|
||||||
|
.trim()
|
||||||
|
.min(1, { message: "Secret path cannot be empty" })
|
||||||
.optional()
|
.optional()
|
||||||
.nullable()
|
.transform((val) => (val ? removeTrailingSlash(val) : undefined)),
|
||||||
.transform((val) => (val ? removeTrailingSlash(val) : val))
|
|
||||||
.transform((val) => (val === "" ? "/" : val)),
|
|
||||||
enforcementLevel: z.nativeEnum(EnforcementLevel).optional(),
|
enforcementLevel: z.nativeEnum(EnforcementLevel).optional(),
|
||||||
allowedSelfApprovals: z.boolean().default(true)
|
allowedSelfApprovals: z.boolean().default(true)
|
||||||
}),
|
}),
|
||||||
|
@ -58,7 +58,7 @@ export const registerSecretApprovalRequestRouter = async (server: FastifyZodProv
|
|||||||
deletedAt: z.date().nullish(),
|
deletedAt: z.date().nullish(),
|
||||||
allowedSelfApprovals: z.boolean()
|
allowedSelfApprovals: z.boolean()
|
||||||
}),
|
}),
|
||||||
committerUser: approvalRequestUser,
|
committerUser: approvalRequestUser.nullish(),
|
||||||
commits: z.object({ op: z.string(), secretId: z.string().nullable().optional() }).array(),
|
commits: z.object({ op: z.string(), secretId: z.string().nullable().optional() }).array(),
|
||||||
environment: z.string(),
|
environment: z.string(),
|
||||||
reviewers: z.object({ userId: z.string(), status: z.string() }).array(),
|
reviewers: z.object({ userId: z.string(), status: z.string() }).array(),
|
||||||
@ -308,7 +308,7 @@ export const registerSecretApprovalRequestRouter = async (server: FastifyZodProv
|
|||||||
}),
|
}),
|
||||||
environment: z.string(),
|
environment: z.string(),
|
||||||
statusChangedByUser: approvalRequestUser.optional(),
|
statusChangedByUser: approvalRequestUser.optional(),
|
||||||
committerUser: approvalRequestUser,
|
committerUser: approvalRequestUser.nullish(),
|
||||||
reviewers: approvalRequestUser.extend({ status: z.string(), comment: z.string().optional() }).array(),
|
reviewers: approvalRequestUser.extend({ status: z.string(), comment: z.string().optional() }).array(),
|
||||||
secretPath: z.string(),
|
secretPath: z.string(),
|
||||||
commits: secretRawSchema
|
commits: secretRawSchema
|
||||||
|
@ -53,7 +53,7 @@ export interface TAccessApprovalPolicyDALFactory
|
|||||||
envId: string;
|
envId: string;
|
||||||
enforcementLevel: string;
|
enforcementLevel: string;
|
||||||
allowedSelfApprovals: boolean;
|
allowedSelfApprovals: boolean;
|
||||||
secretPath?: string | null | undefined;
|
secretPath: string;
|
||||||
deletedAt?: Date | null | undefined;
|
deletedAt?: Date | null | undefined;
|
||||||
environment: {
|
environment: {
|
||||||
id: string;
|
id: string;
|
||||||
@ -93,7 +93,7 @@ export interface TAccessApprovalPolicyDALFactory
|
|||||||
envId: string;
|
envId: string;
|
||||||
enforcementLevel: string;
|
enforcementLevel: string;
|
||||||
allowedSelfApprovals: boolean;
|
allowedSelfApprovals: boolean;
|
||||||
secretPath?: string | null | undefined;
|
secretPath: string;
|
||||||
deletedAt?: Date | null | undefined;
|
deletedAt?: Date | null | undefined;
|
||||||
environment: {
|
environment: {
|
||||||
id: string;
|
id: string;
|
||||||
@ -116,7 +116,7 @@ export interface TAccessApprovalPolicyDALFactory
|
|||||||
envId: string;
|
envId: string;
|
||||||
enforcementLevel: string;
|
enforcementLevel: string;
|
||||||
allowedSelfApprovals: boolean;
|
allowedSelfApprovals: boolean;
|
||||||
secretPath?: string | null | undefined;
|
secretPath: string;
|
||||||
deletedAt?: Date | null | undefined;
|
deletedAt?: Date | null | undefined;
|
||||||
}>;
|
}>;
|
||||||
findLastValidPolicy: (
|
findLastValidPolicy: (
|
||||||
@ -138,7 +138,7 @@ export interface TAccessApprovalPolicyDALFactory
|
|||||||
envId: string;
|
envId: string;
|
||||||
enforcementLevel: string;
|
enforcementLevel: string;
|
||||||
allowedSelfApprovals: boolean;
|
allowedSelfApprovals: boolean;
|
||||||
secretPath?: string | null | undefined;
|
secretPath: string;
|
||||||
deletedAt?: Date | null | undefined;
|
deletedAt?: Date | null | undefined;
|
||||||
}
|
}
|
||||||
| undefined
|
| undefined
|
||||||
@ -190,7 +190,7 @@ export interface TAccessApprovalPolicyServiceFactory {
|
|||||||
envId: string;
|
envId: string;
|
||||||
enforcementLevel: string;
|
enforcementLevel: string;
|
||||||
allowedSelfApprovals: boolean;
|
allowedSelfApprovals: boolean;
|
||||||
secretPath?: string | null | undefined;
|
secretPath: string;
|
||||||
deletedAt?: Date | null | undefined;
|
deletedAt?: Date | null | undefined;
|
||||||
}>;
|
}>;
|
||||||
deleteAccessApprovalPolicy: ({
|
deleteAccessApprovalPolicy: ({
|
||||||
@ -214,7 +214,7 @@ export interface TAccessApprovalPolicyServiceFactory {
|
|||||||
envId: string;
|
envId: string;
|
||||||
enforcementLevel: string;
|
enforcementLevel: string;
|
||||||
allowedSelfApprovals: boolean;
|
allowedSelfApprovals: boolean;
|
||||||
secretPath?: string | null | undefined;
|
secretPath: string;
|
||||||
deletedAt?: Date | null | undefined;
|
deletedAt?: Date | null | undefined;
|
||||||
environment: {
|
environment: {
|
||||||
id: string;
|
id: string;
|
||||||
@ -252,7 +252,7 @@ export interface TAccessApprovalPolicyServiceFactory {
|
|||||||
envId: string;
|
envId: string;
|
||||||
enforcementLevel: string;
|
enforcementLevel: string;
|
||||||
allowedSelfApprovals: boolean;
|
allowedSelfApprovals: boolean;
|
||||||
secretPath?: string | null | undefined;
|
secretPath: string;
|
||||||
deletedAt?: Date | null | undefined;
|
deletedAt?: Date | null | undefined;
|
||||||
}>;
|
}>;
|
||||||
getAccessApprovalPolicyByProjectSlug: ({
|
getAccessApprovalPolicyByProjectSlug: ({
|
||||||
@ -286,7 +286,7 @@ export interface TAccessApprovalPolicyServiceFactory {
|
|||||||
envId: string;
|
envId: string;
|
||||||
enforcementLevel: string;
|
enforcementLevel: string;
|
||||||
allowedSelfApprovals: boolean;
|
allowedSelfApprovals: boolean;
|
||||||
secretPath?: string | null | undefined;
|
secretPath: string;
|
||||||
deletedAt?: Date | null | undefined;
|
deletedAt?: Date | null | undefined;
|
||||||
environment: {
|
environment: {
|
||||||
id: string;
|
id: string;
|
||||||
@ -337,7 +337,7 @@ export interface TAccessApprovalPolicyServiceFactory {
|
|||||||
envId: string;
|
envId: string;
|
||||||
enforcementLevel: string;
|
enforcementLevel: string;
|
||||||
allowedSelfApprovals: boolean;
|
allowedSelfApprovals: boolean;
|
||||||
secretPath?: string | null | undefined;
|
secretPath: string;
|
||||||
deletedAt?: Date | null | undefined;
|
deletedAt?: Date | null | undefined;
|
||||||
environment: {
|
environment: {
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -60,6 +60,26 @@ export const accessApprovalPolicyServiceFactory = ({
|
|||||||
accessApprovalRequestReviewerDAL,
|
accessApprovalRequestReviewerDAL,
|
||||||
orgMembershipDAL
|
orgMembershipDAL
|
||||||
}: TAccessApprovalPolicyServiceFactoryDep): TAccessApprovalPolicyServiceFactory => {
|
}: TAccessApprovalPolicyServiceFactoryDep): TAccessApprovalPolicyServiceFactory => {
|
||||||
|
const $policyExists = async ({
|
||||||
|
envId,
|
||||||
|
secretPath,
|
||||||
|
policyId
|
||||||
|
}: {
|
||||||
|
envId: string;
|
||||||
|
secretPath: string;
|
||||||
|
policyId?: string;
|
||||||
|
}) => {
|
||||||
|
const policy = await accessApprovalPolicyDAL
|
||||||
|
.findOne({
|
||||||
|
envId,
|
||||||
|
secretPath,
|
||||||
|
deletedAt: null
|
||||||
|
})
|
||||||
|
.catch(() => null);
|
||||||
|
|
||||||
|
return policyId ? policy && policy.id !== policyId : Boolean(policy);
|
||||||
|
};
|
||||||
|
|
||||||
const createAccessApprovalPolicy: TAccessApprovalPolicyServiceFactory["createAccessApprovalPolicy"] = async ({
|
const createAccessApprovalPolicy: TAccessApprovalPolicyServiceFactory["createAccessApprovalPolicy"] = async ({
|
||||||
name,
|
name,
|
||||||
actor,
|
actor,
|
||||||
@ -106,6 +126,12 @@ export const accessApprovalPolicyServiceFactory = ({
|
|||||||
const env = await projectEnvDAL.findOne({ slug: environment, projectId: project.id });
|
const env = await projectEnvDAL.findOne({ slug: environment, projectId: project.id });
|
||||||
if (!env) throw new NotFoundError({ message: `Environment with slug '${environment}' not found` });
|
if (!env) throw new NotFoundError({ message: `Environment with slug '${environment}' not found` });
|
||||||
|
|
||||||
|
if (await $policyExists({ envId: env.id, secretPath })) {
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: `A policy for secret path '${secretPath}' already exists in environment '${environment}'`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let approverUserIds = userApprovers;
|
let approverUserIds = userApprovers;
|
||||||
if (userApproverNames.length) {
|
if (userApproverNames.length) {
|
||||||
const approverUsersInDB = await userDAL.find({
|
const approverUsersInDB = await userDAL.find({
|
||||||
@ -279,7 +305,11 @@ export const accessApprovalPolicyServiceFactory = ({
|
|||||||
) as { username: string; sequence?: number }[];
|
) as { username: string; sequence?: number }[];
|
||||||
|
|
||||||
const accessApprovalPolicy = await accessApprovalPolicyDAL.findById(policyId);
|
const accessApprovalPolicy = await accessApprovalPolicyDAL.findById(policyId);
|
||||||
if (!accessApprovalPolicy) throw new BadRequestError({ message: "Approval policy not found" });
|
if (!accessApprovalPolicy) {
|
||||||
|
throw new NotFoundError({
|
||||||
|
message: `Access approval policy with ID '${policyId}' not found`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const currentApprovals = approvals || accessApprovalPolicy.approvals;
|
const currentApprovals = approvals || accessApprovalPolicy.approvals;
|
||||||
if (
|
if (
|
||||||
@ -290,9 +320,18 @@ export const accessApprovalPolicyServiceFactory = ({
|
|||||||
throw new BadRequestError({ message: "Approvals cannot be greater than approvers" });
|
throw new BadRequestError({ message: "Approvals cannot be greater than approvers" });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!accessApprovalPolicy) {
|
if (
|
||||||
throw new NotFoundError({ message: `Secret approval policy with ID '${policyId}' not found` });
|
await $policyExists({
|
||||||
|
envId: accessApprovalPolicy.envId,
|
||||||
|
secretPath: secretPath || accessApprovalPolicy.secretPath,
|
||||||
|
policyId: accessApprovalPolicy.id
|
||||||
|
})
|
||||||
|
) {
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: `A policy for secret path '${secretPath}' already exists in environment '${accessApprovalPolicy.environment.slug}'`
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getProjectPermission({
|
const { permission } = await permissionService.getProjectPermission({
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
|
@ -122,7 +122,7 @@ export interface TAccessApprovalPolicyServiceFactory {
|
|||||||
envId: string;
|
envId: string;
|
||||||
enforcementLevel: string;
|
enforcementLevel: string;
|
||||||
allowedSelfApprovals: boolean;
|
allowedSelfApprovals: boolean;
|
||||||
secretPath?: string | null | undefined;
|
secretPath: string;
|
||||||
deletedAt?: Date | null | undefined;
|
deletedAt?: Date | null | undefined;
|
||||||
}>;
|
}>;
|
||||||
deleteAccessApprovalPolicy: ({
|
deleteAccessApprovalPolicy: ({
|
||||||
@ -146,7 +146,7 @@ export interface TAccessApprovalPolicyServiceFactory {
|
|||||||
envId: string;
|
envId: string;
|
||||||
enforcementLevel: string;
|
enforcementLevel: string;
|
||||||
allowedSelfApprovals: boolean;
|
allowedSelfApprovals: boolean;
|
||||||
secretPath?: string | null | undefined;
|
secretPath: string;
|
||||||
deletedAt?: Date | null | undefined;
|
deletedAt?: Date | null | undefined;
|
||||||
environment: {
|
environment: {
|
||||||
id: string;
|
id: string;
|
||||||
@ -218,7 +218,7 @@ export interface TAccessApprovalPolicyServiceFactory {
|
|||||||
envId: string;
|
envId: string;
|
||||||
enforcementLevel: string;
|
enforcementLevel: string;
|
||||||
allowedSelfApprovals: boolean;
|
allowedSelfApprovals: boolean;
|
||||||
secretPath?: string | null | undefined;
|
secretPath: string;
|
||||||
deletedAt?: Date | null | undefined;
|
deletedAt?: Date | null | undefined;
|
||||||
environment: {
|
environment: {
|
||||||
id: string;
|
id: string;
|
||||||
@ -269,7 +269,7 @@ export interface TAccessApprovalPolicyServiceFactory {
|
|||||||
envId: string;
|
envId: string;
|
||||||
enforcementLevel: string;
|
enforcementLevel: string;
|
||||||
allowedSelfApprovals: boolean;
|
allowedSelfApprovals: boolean;
|
||||||
secretPath?: string | null | undefined;
|
secretPath: string;
|
||||||
deletedAt?: Date | null | undefined;
|
deletedAt?: Date | null | undefined;
|
||||||
environment: {
|
environment: {
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -1711,7 +1711,7 @@ interface SecretApprovalReopened {
|
|||||||
interface SecretApprovalRequest {
|
interface SecretApprovalRequest {
|
||||||
type: EventType.SECRET_APPROVAL_REQUEST;
|
type: EventType.SECRET_APPROVAL_REQUEST;
|
||||||
metadata: {
|
metadata: {
|
||||||
committedBy: string;
|
committedBy?: string | null;
|
||||||
secretApprovalRequestSlug: string;
|
secretApprovalRequestSlug: string;
|
||||||
secretApprovalRequestId: string;
|
secretApprovalRequestId: string;
|
||||||
eventType: SecretApprovalEvent;
|
eventType: SecretApprovalEvent;
|
||||||
|
@ -361,13 +361,6 @@ export const ldapConfigServiceFactory = ({
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const plan = await licenseService.getPlan(orgId);
|
const plan = await licenseService.getPlan(orgId);
|
||||||
if (plan?.slug !== "enterprise" && plan?.memberLimit && plan.membersUsed >= plan.memberLimit) {
|
|
||||||
// limit imposed on number of members allowed / number of members used exceeds the number of members allowed
|
|
||||||
throw new BadRequestError({
|
|
||||||
message: "Failed to create new member via LDAP due to member limit reached. Upgrade plan to add more members."
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (plan?.slug !== "enterprise" && plan?.identityLimit && plan.identitiesUsed >= plan.identityLimit) {
|
if (plan?.slug !== "enterprise" && plan?.identityLimit && plan.identitiesUsed >= plan.identityLimit) {
|
||||||
// limit imposed on number of identities allowed / number of identities used exceeds the number of identities allowed
|
// limit imposed on number of identities allowed / number of identities used exceeds the number of identities allowed
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
export const BillingPlanRows = {
|
export const BillingPlanRows = {
|
||||||
MemberLimit: { name: "Organization member limit", field: "memberLimit" },
|
|
||||||
IdentityLimit: { name: "Organization identity limit", field: "identityLimit" },
|
IdentityLimit: { name: "Organization identity limit", field: "identityLimit" },
|
||||||
WorkspaceLimit: { name: "Project limit", field: "workspaceLimit" },
|
WorkspaceLimit: { name: "Project limit", field: "workspaceLimit" },
|
||||||
EnvironmentLimit: { name: "Environment limit", field: "environmentLimit" },
|
EnvironmentLimit: { name: "Environment limit", field: "environmentLimit" },
|
||||||
|
@ -442,9 +442,7 @@ export const licenseServiceFactory = ({
|
|||||||
rows: data.rows.map((el) => {
|
rows: data.rows.map((el) => {
|
||||||
let used = "-";
|
let used = "-";
|
||||||
|
|
||||||
if (el.name === BillingPlanRows.MemberLimit.name) {
|
if (el.name === BillingPlanRows.WorkspaceLimit.name) {
|
||||||
used = orgMembersUsed.toString();
|
|
||||||
} else if (el.name === BillingPlanRows.WorkspaceLimit.name) {
|
|
||||||
used = projectCount.toString();
|
used = projectCount.toString();
|
||||||
} else if (el.name === BillingPlanRows.IdentityLimit.name) {
|
} else if (el.name === BillingPlanRows.IdentityLimit.name) {
|
||||||
used = (identityUsed + orgMembersUsed).toString();
|
used = (identityUsed + orgMembersUsed).toString();
|
||||||
@ -464,12 +462,10 @@ export const licenseServiceFactory = ({
|
|||||||
const allowed = onPremFeatures[field as keyof TFeatureSet];
|
const allowed = onPremFeatures[field as keyof TFeatureSet];
|
||||||
let used = "-";
|
let used = "-";
|
||||||
|
|
||||||
if (field === BillingPlanRows.MemberLimit.field) {
|
if (field === BillingPlanRows.WorkspaceLimit.field) {
|
||||||
used = orgMembersUsed.toString();
|
|
||||||
} else if (field === BillingPlanRows.WorkspaceLimit.field) {
|
|
||||||
used = projectCount.toString();
|
used = projectCount.toString();
|
||||||
} else if (field === BillingPlanRows.IdentityLimit.field) {
|
} else if (field === BillingPlanRows.IdentityLimit.field) {
|
||||||
used = identityUsed.toString();
|
used = (identityUsed + orgMembersUsed).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -311,13 +311,6 @@ export const samlConfigServiceFactory = ({
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const plan = await licenseService.getPlan(orgId);
|
const plan = await licenseService.getPlan(orgId);
|
||||||
if (plan?.slug !== "enterprise" && plan?.memberLimit && plan.membersUsed >= plan.memberLimit) {
|
|
||||||
// limit imposed on number of members allowed / number of members used exceeds the number of members allowed
|
|
||||||
throw new BadRequestError({
|
|
||||||
message: "Failed to create new member via SAML due to member limit reached. Upgrade plan to add more members."
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (plan?.slug !== "enterprise" && plan?.identityLimit && plan.identitiesUsed >= plan.identityLimit) {
|
if (plan?.slug !== "enterprise" && plan?.identityLimit && plan.identitiesUsed >= plan.identityLimit) {
|
||||||
// limit imposed on number of identities allowed / number of identities used exceeds the number of identities allowed
|
// limit imposed on number of identities allowed / number of identities used exceeds the number of identities allowed
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
|
@ -55,6 +55,26 @@ export const secretApprovalPolicyServiceFactory = ({
|
|||||||
licenseService,
|
licenseService,
|
||||||
secretApprovalRequestDAL
|
secretApprovalRequestDAL
|
||||||
}: TSecretApprovalPolicyServiceFactoryDep) => {
|
}: TSecretApprovalPolicyServiceFactoryDep) => {
|
||||||
|
const $policyExists = async ({
|
||||||
|
envId,
|
||||||
|
secretPath,
|
||||||
|
policyId
|
||||||
|
}: {
|
||||||
|
envId: string;
|
||||||
|
secretPath: string;
|
||||||
|
policyId?: string;
|
||||||
|
}) => {
|
||||||
|
const policy = await secretApprovalPolicyDAL
|
||||||
|
.findOne({
|
||||||
|
envId,
|
||||||
|
secretPath,
|
||||||
|
deletedAt: null
|
||||||
|
})
|
||||||
|
.catch(() => null);
|
||||||
|
|
||||||
|
return policyId ? policy && policy.id !== policyId : Boolean(policy);
|
||||||
|
};
|
||||||
|
|
||||||
const createSecretApprovalPolicy = async ({
|
const createSecretApprovalPolicy = async ({
|
||||||
name,
|
name,
|
||||||
actor,
|
actor,
|
||||||
@ -106,10 +126,17 @@ export const secretApprovalPolicyServiceFactory = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const env = await projectEnvDAL.findOne({ slug: environment, projectId });
|
const env = await projectEnvDAL.findOne({ slug: environment, projectId });
|
||||||
if (!env)
|
if (!env) {
|
||||||
throw new NotFoundError({
|
throw new NotFoundError({
|
||||||
message: `Environment with slug '${environment}' not found in project with ID ${projectId}`
|
message: `Environment with slug '${environment}' not found in project with ID ${projectId}`
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (await $policyExists({ envId: env.id, secretPath })) {
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: `A policy for secret path '${secretPath}' already exists in environment '${environment}'`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let groupBypassers: string[] = [];
|
let groupBypassers: string[] = [];
|
||||||
let bypasserUserIds: string[] = [];
|
let bypasserUserIds: string[] = [];
|
||||||
@ -260,6 +287,18 @@ export const secretApprovalPolicyServiceFactory = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
await $policyExists({
|
||||||
|
envId: secretApprovalPolicy.envId,
|
||||||
|
secretPath: secretPath || secretApprovalPolicy.secretPath,
|
||||||
|
policyId: secretApprovalPolicy.id
|
||||||
|
})
|
||||||
|
) {
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: `A policy for secret path '${secretPath}' already exists in environment '${secretApprovalPolicy.environment.slug}'`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getProjectPermission({
|
const { permission } = await permissionService.getProjectPermission({
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
|
@ -4,7 +4,7 @@ import { ApproverType, BypasserType } from "../access-approval-policy/access-app
|
|||||||
|
|
||||||
export type TCreateSapDTO = {
|
export type TCreateSapDTO = {
|
||||||
approvals: number;
|
approvals: number;
|
||||||
secretPath?: string | null;
|
secretPath: string;
|
||||||
environment: string;
|
environment: string;
|
||||||
approvers: ({ type: ApproverType.Group; id: string } | { type: ApproverType.User; id?: string; username?: string })[];
|
approvers: ({ type: ApproverType.Group; id: string } | { type: ApproverType.User; id?: string; username?: string })[];
|
||||||
bypassers?: (
|
bypassers?: (
|
||||||
@ -20,7 +20,7 @@ export type TCreateSapDTO = {
|
|||||||
export type TUpdateSapDTO = {
|
export type TUpdateSapDTO = {
|
||||||
secretPolicyId: string;
|
secretPolicyId: string;
|
||||||
approvals?: number;
|
approvals?: number;
|
||||||
secretPath?: string | null;
|
secretPath?: string;
|
||||||
approvers: ({ type: ApproverType.Group; id: string } | { type: ApproverType.User; id?: string; username?: string })[];
|
approvers: ({ type: ApproverType.Group; id: string } | { type: ApproverType.User; id?: string; username?: string })[];
|
||||||
bypassers?: (
|
bypassers?: (
|
||||||
| { type: BypasserType.Group; id: string }
|
| { type: BypasserType.Group; id: string }
|
||||||
|
@ -45,7 +45,7 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => {
|
|||||||
`${TableName.SecretApprovalRequest}.statusChangedByUserId`,
|
`${TableName.SecretApprovalRequest}.statusChangedByUserId`,
|
||||||
`statusChangedByUser.id`
|
`statusChangedByUser.id`
|
||||||
)
|
)
|
||||||
.join<TUsers>(
|
.leftJoin<TUsers>(
|
||||||
db(TableName.Users).as("committerUser"),
|
db(TableName.Users).as("committerUser"),
|
||||||
`${TableName.SecretApprovalRequest}.committerUserId`,
|
`${TableName.SecretApprovalRequest}.committerUserId`,
|
||||||
`committerUser.id`
|
`committerUser.id`
|
||||||
@ -173,13 +173,15 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => {
|
|||||||
username: el.statusChangedByUserUsername
|
username: el.statusChangedByUserUsername
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
committerUser: {
|
committerUser: el.committerUserId
|
||||||
|
? {
|
||||||
userId: el.committerUserId,
|
userId: el.committerUserId,
|
||||||
email: el.committerUserEmail,
|
email: el.committerUserEmail,
|
||||||
firstName: el.committerUserFirstName,
|
firstName: el.committerUserFirstName,
|
||||||
lastName: el.committerUserLastName,
|
lastName: el.committerUserLastName,
|
||||||
username: el.committerUserUsername
|
username: el.committerUserUsername
|
||||||
},
|
}
|
||||||
|
: null,
|
||||||
policy: {
|
policy: {
|
||||||
id: el.policyId,
|
id: el.policyId,
|
||||||
name: el.policyName,
|
name: el.policyName,
|
||||||
@ -377,7 +379,7 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => {
|
|||||||
`${TableName.SecretApprovalPolicyBypasser}.bypasserGroupId`,
|
`${TableName.SecretApprovalPolicyBypasser}.bypasserGroupId`,
|
||||||
`bypasserUserGroupMembership.groupId`
|
`bypasserUserGroupMembership.groupId`
|
||||||
)
|
)
|
||||||
.join<TUsers>(
|
.leftJoin<TUsers>(
|
||||||
db(TableName.Users).as("committerUser"),
|
db(TableName.Users).as("committerUser"),
|
||||||
`${TableName.SecretApprovalRequest}.committerUserId`,
|
`${TableName.SecretApprovalRequest}.committerUserId`,
|
||||||
`committerUser.id`
|
`committerUser.id`
|
||||||
@ -488,13 +490,15 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => {
|
|||||||
enforcementLevel: el.policyEnforcementLevel,
|
enforcementLevel: el.policyEnforcementLevel,
|
||||||
allowedSelfApprovals: el.policyAllowedSelfApprovals
|
allowedSelfApprovals: el.policyAllowedSelfApprovals
|
||||||
},
|
},
|
||||||
committerUser: {
|
committerUser: el.committerUserId
|
||||||
|
? {
|
||||||
userId: el.committerUserId,
|
userId: el.committerUserId,
|
||||||
email: el.committerUserEmail,
|
email: el.committerUserEmail,
|
||||||
firstName: el.committerUserFirstName,
|
firstName: el.committerUserFirstName,
|
||||||
lastName: el.committerUserLastName,
|
lastName: el.committerUserLastName,
|
||||||
username: el.committerUserUsername
|
username: el.committerUserUsername
|
||||||
}
|
}
|
||||||
|
: null
|
||||||
}),
|
}),
|
||||||
childrenMapper: [
|
childrenMapper: [
|
||||||
{
|
{
|
||||||
@ -581,7 +585,7 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => {
|
|||||||
`${TableName.SecretApprovalPolicyBypasser}.bypasserGroupId`,
|
`${TableName.SecretApprovalPolicyBypasser}.bypasserGroupId`,
|
||||||
`bypasserUserGroupMembership.groupId`
|
`bypasserUserGroupMembership.groupId`
|
||||||
)
|
)
|
||||||
.join<TUsers>(
|
.leftJoin<TUsers>(
|
||||||
db(TableName.Users).as("committerUser"),
|
db(TableName.Users).as("committerUser"),
|
||||||
`${TableName.SecretApprovalRequest}.committerUserId`,
|
`${TableName.SecretApprovalRequest}.committerUserId`,
|
||||||
`committerUser.id`
|
`committerUser.id`
|
||||||
@ -693,13 +697,15 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => {
|
|||||||
enforcementLevel: el.policyEnforcementLevel,
|
enforcementLevel: el.policyEnforcementLevel,
|
||||||
allowedSelfApprovals: el.policyAllowedSelfApprovals
|
allowedSelfApprovals: el.policyAllowedSelfApprovals
|
||||||
},
|
},
|
||||||
committerUser: {
|
committerUser: el.committerUserId
|
||||||
|
? {
|
||||||
userId: el.committerUserId,
|
userId: el.committerUserId,
|
||||||
email: el.committerUserEmail,
|
email: el.committerUserEmail,
|
||||||
firstName: el.committerUserFirstName,
|
firstName: el.committerUserFirstName,
|
||||||
lastName: el.committerUserLastName,
|
lastName: el.committerUserLastName,
|
||||||
username: el.committerUserUsername
|
username: el.committerUserUsername
|
||||||
}
|
}
|
||||||
|
: null
|
||||||
}),
|
}),
|
||||||
childrenMapper: [
|
childrenMapper: [
|
||||||
{
|
{
|
||||||
|
@ -1320,7 +1320,7 @@ export const secretApprovalRequestServiceFactory = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const env = await projectEnvDAL.findOne({ id: policy.envId });
|
const env = await projectEnvDAL.findOne({ id: policy.envId });
|
||||||
const user = await userDAL.findById(secretApprovalRequest.committerUserId);
|
const user = await userDAL.findById(actorId);
|
||||||
|
|
||||||
await triggerWorkflowIntegrationNotification({
|
await triggerWorkflowIntegrationNotification({
|
||||||
input: {
|
input: {
|
||||||
@ -1657,7 +1657,7 @@ export const secretApprovalRequestServiceFactory = ({
|
|||||||
return { ...doc, commits: approvalCommits };
|
return { ...doc, commits: approvalCommits };
|
||||||
});
|
});
|
||||||
|
|
||||||
const user = await userDAL.findById(secretApprovalRequest.committerUserId);
|
const user = await userDAL.findById(actorId);
|
||||||
const env = await projectEnvDAL.findOne({ id: policy.envId });
|
const env = await projectEnvDAL.findOne({ id: policy.envId });
|
||||||
|
|
||||||
await triggerWorkflowIntegrationNotification({
|
await triggerWorkflowIntegrationNotification({
|
||||||
|
@ -37,7 +37,8 @@ import {
|
|||||||
TQueueSecretScanningDataSourceFullScan,
|
TQueueSecretScanningDataSourceFullScan,
|
||||||
TQueueSecretScanningResourceDiffScan,
|
TQueueSecretScanningResourceDiffScan,
|
||||||
TQueueSecretScanningSendNotification,
|
TQueueSecretScanningSendNotification,
|
||||||
TSecretScanningDataSourceWithConnection
|
TSecretScanningDataSourceWithConnection,
|
||||||
|
TSecretScanningFinding
|
||||||
} from "./secret-scanning-v2-types";
|
} from "./secret-scanning-v2-types";
|
||||||
|
|
||||||
type TSecretRotationV2QueueServiceFactoryDep = {
|
type TSecretRotationV2QueueServiceFactoryDep = {
|
||||||
@ -459,13 +460,16 @@ export const secretScanningV2QueueServiceFactory = async ({
|
|||||||
const newFindings = allFindings.filter((finding) => finding.scanId === scanId);
|
const newFindings = allFindings.filter((finding) => finding.scanId === scanId);
|
||||||
|
|
||||||
if (newFindings.length) {
|
if (newFindings.length) {
|
||||||
|
const finding = newFindings[0] as TSecretScanningFinding;
|
||||||
await queueService.queuePg(QueueJobs.SecretScanningV2SendNotification, {
|
await queueService.queuePg(QueueJobs.SecretScanningV2SendNotification, {
|
||||||
status: SecretScanningScanStatus.Completed,
|
status: SecretScanningScanStatus.Completed,
|
||||||
resourceName: resource.name,
|
resourceName: resource.name,
|
||||||
isDiffScan: true,
|
isDiffScan: true,
|
||||||
dataSource,
|
dataSource,
|
||||||
numberOfSecrets: newFindings.length,
|
numberOfSecrets: newFindings.length,
|
||||||
scanId
|
scanId,
|
||||||
|
authorName: finding?.details?.author,
|
||||||
|
authorEmail: finding?.details?.email
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -582,8 +586,8 @@ export const secretScanningV2QueueServiceFactory = async ({
|
|||||||
substitutions:
|
substitutions:
|
||||||
payload.status === SecretScanningScanStatus.Completed
|
payload.status === SecretScanningScanStatus.Completed
|
||||||
? {
|
? {
|
||||||
authorName: "Jim",
|
authorName: payload.authorName,
|
||||||
authorEmail: "jim@infisical.com",
|
authorEmail: payload.authorEmail,
|
||||||
resourceName,
|
resourceName,
|
||||||
numberOfSecrets: payload.numberOfSecrets,
|
numberOfSecrets: payload.numberOfSecrets,
|
||||||
isDiffScan: payload.isDiffScan,
|
isDiffScan: payload.isDiffScan,
|
||||||
|
@ -119,7 +119,14 @@ export type TQueueSecretScanningSendNotification = {
|
|||||||
resourceName: string;
|
resourceName: string;
|
||||||
} & (
|
} & (
|
||||||
| { status: SecretScanningScanStatus.Failed; errorMessage: string }
|
| { status: SecretScanningScanStatus.Failed; errorMessage: string }
|
||||||
| { status: SecretScanningScanStatus.Completed; numberOfSecrets: number; scanId: string; isDiffScan: boolean }
|
| {
|
||||||
|
status: SecretScanningScanStatus.Completed;
|
||||||
|
numberOfSecrets: number;
|
||||||
|
scanId: string;
|
||||||
|
isDiffScan: boolean;
|
||||||
|
authorName?: string;
|
||||||
|
authorEmail?: string;
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
export type TCloneRepository = {
|
export type TCloneRepository = {
|
||||||
|
@ -912,14 +912,6 @@ export const orgServiceFactory = ({
|
|||||||
|
|
||||||
// if there exist no org membership we set is as given by the request
|
// if there exist no org membership we set is as given by the request
|
||||||
if (!inviteeOrgMembership) {
|
if (!inviteeOrgMembership) {
|
||||||
if (plan?.slug !== "enterprise" && plan?.memberLimit && plan.membersUsed >= plan.memberLimit) {
|
|
||||||
// limit imposed on number of members allowed / number of members used exceeds the number of members allowed
|
|
||||||
throw new BadRequestError({
|
|
||||||
name: "InviteUser",
|
|
||||||
message: "Failed to invite member due to member limit reached. Upgrade plan to invite more members."
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (plan?.slug !== "enterprise" && plan?.identityLimit && plan.identitiesUsed >= plan.identityLimit) {
|
if (plan?.slug !== "enterprise" && plan?.identityLimit && plan.identitiesUsed >= plan.identityLimit) {
|
||||||
// limit imposed on number of identities allowed / number of identities used exceeds the number of identities allowed
|
// limit imposed on number of identities allowed / number of identities used exceeds the number of identities allowed
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
|
@ -1,6 +1,32 @@
|
|||||||
FROM node:20-alpine
|
FROM node:20-alpine AS builder
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
RUN npm install -g mint
|
|
||||||
|
RUN npm install -g mint@4.2.13
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
|
# Install a local version of our OpenAPI spec
|
||||||
|
RUN apk add --no-cache wget jq && \
|
||||||
|
wget -O spec.json https://app.infisical.com/api/docs/json && \
|
||||||
|
jq '.api.openapi = "./spec.json"' docs.json > temp.json && \
|
||||||
|
mv temp.json docs.json
|
||||||
|
|
||||||
|
# Run mint dev briefly to download the web client
|
||||||
|
RUN timeout 30 mint dev || true
|
||||||
|
|
||||||
|
FROM node:20-alpine
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
RUN npm install -g mint@4.2.13
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
COPY --from=builder /root/.mintlify /root/.mintlify
|
||||||
|
COPY --from=builder /app/docs.json /app/docs.json
|
||||||
|
COPY --from=builder /app/spec.json /app/spec.json
|
||||||
|
|
||||||
EXPOSE 3000
|
EXPOSE 3000
|
||||||
|
|
||||||
CMD ["mint", "dev"]
|
CMD ["mint", "dev"]
|
||||||
|
@ -78,7 +78,10 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"group": "Infisical SSH",
|
"group": "Infisical SSH",
|
||||||
"pages": ["documentation/platform/ssh/overview", "documentation/platform/ssh/host-groups"]
|
"pages": [
|
||||||
|
"documentation/platform/ssh/overview",
|
||||||
|
"documentation/platform/ssh/host-groups"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"group": "Key Management (KMS)",
|
"group": "Key Management (KMS)",
|
||||||
@ -375,7 +378,10 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"group": "Architecture",
|
"group": "Architecture",
|
||||||
"pages": ["internals/architecture/components", "internals/architecture/cloud"]
|
"pages": [
|
||||||
|
"internals/architecture/components",
|
||||||
|
"internals/architecture/cloud"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"internals/security",
|
"internals/security",
|
||||||
"internals/service-tokens"
|
"internals/service-tokens"
|
||||||
@ -546,7 +552,10 @@
|
|||||||
"integrations/cloud/gcp-secret-manager",
|
"integrations/cloud/gcp-secret-manager",
|
||||||
{
|
{
|
||||||
"group": "Cloudflare",
|
"group": "Cloudflare",
|
||||||
"pages": ["integrations/cloud/cloudflare-pages", "integrations/cloud/cloudflare-workers"]
|
"pages": [
|
||||||
|
"integrations/cloud/cloudflare-pages",
|
||||||
|
"integrations/cloud/cloudflare-workers"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"integrations/cloud/terraform-cloud",
|
"integrations/cloud/terraform-cloud",
|
||||||
"integrations/cloud/databricks",
|
"integrations/cloud/databricks",
|
||||||
@ -658,7 +667,11 @@
|
|||||||
"cli/commands/reset",
|
"cli/commands/reset",
|
||||||
{
|
{
|
||||||
"group": "infisical scan",
|
"group": "infisical scan",
|
||||||
"pages": ["cli/commands/scan", "cli/commands/scan-git-changes", "cli/commands/scan-install"]
|
"pages": [
|
||||||
|
"cli/commands/scan",
|
||||||
|
"cli/commands/scan-git-changes",
|
||||||
|
"cli/commands/scan-install"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -982,7 +995,9 @@
|
|||||||
"pages": [
|
"pages": [
|
||||||
{
|
{
|
||||||
"group": "Kubernetes",
|
"group": "Kubernetes",
|
||||||
"pages": ["api-reference/endpoints/dynamic-secrets/kubernetes/create-lease"]
|
"pages": [
|
||||||
|
"api-reference/endpoints/dynamic-secrets/kubernetes/create-lease"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"api-reference/endpoints/dynamic-secrets/create",
|
"api-reference/endpoints/dynamic-secrets/create",
|
||||||
"api-reference/endpoints/dynamic-secrets/update",
|
"api-reference/endpoints/dynamic-secrets/update",
|
||||||
|
@ -29,10 +29,6 @@ export const ROUTE_PATHS = Object.freeze({
|
|||||||
"/_authenticate/_inject-org-details/_org-layout/organization/settings/oauth/callback"
|
"/_authenticate/_inject-org-details/_org-layout/organization/settings/oauth/callback"
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
SsoPage: setRoute(
|
|
||||||
"/organization/sso",
|
|
||||||
"/_authenticate/_inject-org-details/_org-layout/organization/sso"
|
|
||||||
),
|
|
||||||
SecretSharing: setRoute(
|
SecretSharing: setRoute(
|
||||||
"/organization/secret-sharing",
|
"/organization/secret-sharing",
|
||||||
"/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing/"
|
"/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing/"
|
||||||
|
@ -170,7 +170,7 @@ export type TCreateAccessPolicyDTO = {
|
|||||||
approvers?: Approver[];
|
approvers?: Approver[];
|
||||||
bypassers?: Bypasser[];
|
bypassers?: Bypasser[];
|
||||||
approvals?: number;
|
approvals?: number;
|
||||||
secretPath?: string;
|
secretPath: string;
|
||||||
enforcementLevel?: EnforcementLevel;
|
enforcementLevel?: EnforcementLevel;
|
||||||
allowedSelfApprovals: boolean;
|
allowedSelfApprovals: boolean;
|
||||||
approvalsRequired?: { numberOfApprovals: number; stepNumber: number }[];
|
approvalsRequired?: { numberOfApprovals: number; stepNumber: number }[];
|
||||||
|
@ -3,6 +3,7 @@ import { useMutation, useQueryClient } from "@tanstack/react-query";
|
|||||||
import { apiRequest } from "@app/config/request";
|
import { apiRequest } from "@app/config/request";
|
||||||
|
|
||||||
import { organizationKeys } from "../organization/queries";
|
import { organizationKeys } from "../organization/queries";
|
||||||
|
import { subscriptionQueryKeys } from "../subscriptions/queries";
|
||||||
import { identitiesKeys } from "./queries";
|
import { identitiesKeys } from "./queries";
|
||||||
import {
|
import {
|
||||||
AddIdentityAliCloudAuthDTO,
|
AddIdentityAliCloudAuthDTO,
|
||||||
@ -82,6 +83,9 @@ export const useCreateIdentity = () => {
|
|||||||
queryClient.invalidateQueries({
|
queryClient.invalidateQueries({
|
||||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||||
});
|
});
|
||||||
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: subscriptionQueryKeys.getOrgSubsription(organizationId)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -123,6 +127,9 @@ export const useDeleteIdentity = () => {
|
|||||||
queryClient.invalidateQueries({
|
queryClient.invalidateQueries({
|
||||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||||
});
|
});
|
||||||
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: subscriptionQueryKeys.getOrgSubsription(organizationId)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -49,7 +49,7 @@ export type TCreateSecretPolicyDTO = {
|
|||||||
workspaceId: string;
|
workspaceId: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
environment: string;
|
environment: string;
|
||||||
secretPath?: string | null;
|
secretPath: string;
|
||||||
approvers?: Approver[];
|
approvers?: Approver[];
|
||||||
bypassers?: Bypasser[];
|
bypassers?: Bypasser[];
|
||||||
approvals?: number;
|
approvals?: number;
|
||||||
@ -62,7 +62,7 @@ export type TUpdateSecretPolicyDTO = {
|
|||||||
name?: string;
|
name?: string;
|
||||||
approvers?: Approver[];
|
approvers?: Approver[];
|
||||||
bypassers?: Bypasser[];
|
bypassers?: Bypasser[];
|
||||||
secretPath?: string | null;
|
secretPath?: string;
|
||||||
approvals?: number;
|
approvals?: number;
|
||||||
allowedSelfApprovals?: boolean;
|
allowedSelfApprovals?: boolean;
|
||||||
enforcementLevel?: EnforcementLevel;
|
enforcementLevel?: EnforcementLevel;
|
||||||
|
@ -9,6 +9,7 @@ import { APIKeyDataV2 } from "../apiKeys/types";
|
|||||||
import { MfaMethod } from "../auth/types";
|
import { MfaMethod } from "../auth/types";
|
||||||
import { TGroupWithProjectMemberships } from "../groups/types";
|
import { TGroupWithProjectMemberships } from "../groups/types";
|
||||||
import { setAuthToken } from "../reactQuery";
|
import { setAuthToken } from "../reactQuery";
|
||||||
|
import { subscriptionQueryKeys } from "../subscriptions/queries";
|
||||||
import { workspaceKeys } from "../workspace";
|
import { workspaceKeys } from "../workspace";
|
||||||
import { userKeys } from "./query-keys";
|
import { userKeys } from "./query-keys";
|
||||||
import {
|
import {
|
||||||
@ -188,6 +189,9 @@ export const useAddUsersToOrg = () => {
|
|||||||
},
|
},
|
||||||
onSuccess: (_, { organizationId, projects }) => {
|
onSuccess: (_, { organizationId, projects }) => {
|
||||||
queryClient.invalidateQueries({ queryKey: userKeys.getOrgUsers(organizationId) });
|
queryClient.invalidateQueries({ queryKey: userKeys.getOrgUsers(organizationId) });
|
||||||
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: subscriptionQueryKeys.getOrgSubsription(organizationId)
|
||||||
|
});
|
||||||
|
|
||||||
projects?.forEach((project) => {
|
projects?.forEach((project) => {
|
||||||
if (project.slug) {
|
if (project.slug) {
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
faBook,
|
faBook,
|
||||||
faCheckCircle,
|
|
||||||
faCog,
|
faCog,
|
||||||
faCubes,
|
faCubes,
|
||||||
faDoorClosed,
|
faDoorClosed,
|
||||||
@ -100,18 +99,6 @@ export const OrgSidebar = ({ isHidden }: Props) => {
|
|||||||
</MenuItem>
|
</MenuItem>
|
||||||
)}
|
)}
|
||||||
</Link>
|
</Link>
|
||||||
<Link to="/organization/sso">
|
|
||||||
{({ isActive }) => (
|
|
||||||
<MenuItem isSelected={isActive}>
|
|
||||||
<div className="mx-1 flex gap-2">
|
|
||||||
<div className="w-6">
|
|
||||||
<FontAwesomeIcon icon={faCheckCircle} className="mr-4" />
|
|
||||||
</div>
|
|
||||||
SSO Settings
|
|
||||||
</div>
|
|
||||||
</MenuItem>
|
|
||||||
)}
|
|
||||||
</Link>
|
|
||||||
<Link to="/organization/settings">
|
<Link to="/organization/settings">
|
||||||
{({ isActive }) => (
|
{({ isActive }) => (
|
||||||
<MenuItem isSelected={isActive}>
|
<MenuItem isSelected={isActive}>
|
||||||
|
@ -39,10 +39,6 @@ export const OrgMembersSection = () => {
|
|||||||
const { mutateAsync: deleteMutateAsync } = useDeleteOrgMembership();
|
const { mutateAsync: deleteMutateAsync } = useDeleteOrgMembership();
|
||||||
const { mutateAsync: updateOrgMembership } = useUpdateOrgMembership();
|
const { mutateAsync: updateOrgMembership } = useUpdateOrgMembership();
|
||||||
|
|
||||||
const isMoreUsersAllowed = subscription?.memberLimit
|
|
||||||
? subscription.membersUsed < subscription.memberLimit
|
|
||||||
: true;
|
|
||||||
|
|
||||||
const isMoreIdentitiesAllowed = subscription?.identityLimit
|
const isMoreIdentitiesAllowed = subscription?.identityLimit
|
||||||
? subscription.identitiesUsed < subscription.identityLimit
|
? subscription.identitiesUsed < subscription.identityLimit
|
||||||
: true;
|
: true;
|
||||||
@ -58,7 +54,7 @@ export const OrgMembersSection = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((!isMoreUsersAllowed || !isMoreIdentitiesAllowed) && !isEnterprise) {
|
if (!isMoreIdentitiesAllowed && !isEnterprise) {
|
||||||
handlePopUpOpen("upgradePlan", {
|
handlePopUpOpen("upgradePlan", {
|
||||||
description: "You can add more members if you upgrade your Infisical plan."
|
description: "You can add more members if you upgrade your Infisical plan."
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
import { Link } from "@tanstack/react-router";
|
|
||||||
|
|
||||||
import { NoticeBannerV2 } from "@app/components/v2/NoticeBannerV2/NoticeBannerV2";
|
|
||||||
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/context";
|
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/context";
|
||||||
import { withPermission } from "@app/hoc";
|
import { withPermission } from "@app/hoc";
|
||||||
|
|
||||||
@ -11,21 +8,6 @@ export const OrgSecurityTab = withPermission(
|
|||||||
() => {
|
() => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<NoticeBannerV2
|
|
||||||
className="mx-auto mb-4"
|
|
||||||
titleClassName="text-base"
|
|
||||||
title="Single Sign-On (SSO) Settings"
|
|
||||||
>
|
|
||||||
<p className="mt-1 text-mineshaft-300">
|
|
||||||
SSO Settings have been relocated:{" "}
|
|
||||||
<Link
|
|
||||||
className="text-mineshaft-200 underline underline-offset-2"
|
|
||||||
to="/organization/sso"
|
|
||||||
>
|
|
||||||
Click here to view SSO Settings
|
|
||||||
</Link>
|
|
||||||
</p>
|
|
||||||
</NoticeBannerV2>
|
|
||||||
<OrgGenericAuthSection />
|
<OrgGenericAuthSection />
|
||||||
<OrgUserAccessTokenLimitSection />
|
<OrgUserAccessTokenLimitSection />
|
||||||
</>
|
</>
|
||||||
|
@ -9,8 +9,10 @@ import { ImportTab } from "../ImportTab";
|
|||||||
import { KmipTab } from "../KmipTab/OrgKmipTab";
|
import { KmipTab } from "../KmipTab/OrgKmipTab";
|
||||||
import { OrgEncryptionTab } from "../OrgEncryptionTab";
|
import { OrgEncryptionTab } from "../OrgEncryptionTab";
|
||||||
import { OrgGeneralTab } from "../OrgGeneralTab";
|
import { OrgGeneralTab } from "../OrgGeneralTab";
|
||||||
|
import { OrgProvisioningTab } from "../OrgProvisioningTab";
|
||||||
import { OrgSecurityTab } from "../OrgSecurityTab";
|
import { OrgSecurityTab } from "../OrgSecurityTab";
|
||||||
import { OrgWorkflowIntegrationTab } from "../OrgWorkflowIntegrationTab/OrgWorkflowIntegrationTab";
|
import { OrgSsoTab } from "../OrgSsoTab";
|
||||||
|
import { OrgWorkflowIntegrationTab } from "../OrgWorkflowIntegrationTab";
|
||||||
import { ProjectTemplatesTab } from "../ProjectTemplatesTab";
|
import { ProjectTemplatesTab } from "../ProjectTemplatesTab";
|
||||||
|
|
||||||
export const OrgTabGroup = () => {
|
export const OrgTabGroup = () => {
|
||||||
@ -19,6 +21,16 @@ export const OrgTabGroup = () => {
|
|||||||
});
|
});
|
||||||
const tabs = [
|
const tabs = [
|
||||||
{ name: "General", key: "tab-org-general", component: OrgGeneralTab },
|
{ name: "General", key: "tab-org-general", component: OrgGeneralTab },
|
||||||
|
{
|
||||||
|
name: "SSO",
|
||||||
|
key: "sso-settings",
|
||||||
|
component: OrgSsoTab
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Provisioning",
|
||||||
|
key: "provisioning-settings",
|
||||||
|
component: OrgProvisioningTab
|
||||||
|
},
|
||||||
{ name: "Security", key: "tab-org-security", component: OrgSecurityTab },
|
{ name: "Security", key: "tab-org-security", component: OrgSecurityTab },
|
||||||
{ name: "Encryption", key: "tab-org-encryption", component: OrgEncryptionTab },
|
{ name: "Encryption", key: "tab-org-encryption", component: OrgEncryptionTab },
|
||||||
{
|
{
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
export * from "./OrgWorkflowIntegrationTab";
|
@ -1,21 +0,0 @@
|
|||||||
import { Helmet } from "react-helmet";
|
|
||||||
|
|
||||||
import { PageHeader } from "@app/components/v2";
|
|
||||||
|
|
||||||
import { SsoTabGroup } from "./components/SsoTabGroup";
|
|
||||||
|
|
||||||
export const SsoPage = () => {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Helmet>
|
|
||||||
<title>Single Sign-On (SSO)</title>
|
|
||||||
</Helmet>
|
|
||||||
<div className="flex w-full justify-center bg-bunker-800 text-white">
|
|
||||||
<div className="w-full max-w-7xl">
|
|
||||||
<PageHeader title="Single Sign-On (SSO)" />
|
|
||||||
<SsoTabGroup />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,37 +0,0 @@
|
|||||||
import { useState } from "react";
|
|
||||||
import { useSearch } from "@tanstack/react-router";
|
|
||||||
|
|
||||||
import { Tab, TabList, TabPanel, Tabs } from "@app/components/v2";
|
|
||||||
import { ROUTE_PATHS } from "@app/const/routes";
|
|
||||||
|
|
||||||
import { OrgProvisioningTab } from "../OrgProvisioningTab";
|
|
||||||
import { OrgSsoTab } from "../OrgSsoTab";
|
|
||||||
|
|
||||||
export const SsoTabGroup = () => {
|
|
||||||
const search = useSearch({
|
|
||||||
from: ROUTE_PATHS.Organization.SsoPage.id
|
|
||||||
});
|
|
||||||
const tabs = [
|
|
||||||
{ name: "General", key: "tab-sso-auth", component: OrgSsoTab },
|
|
||||||
{ name: "Provisioning", key: "tab-sso-identity", component: OrgProvisioningTab }
|
|
||||||
];
|
|
||||||
|
|
||||||
const [selectedTab, setSelectedTab] = useState(search.selectedTab || tabs[0].key);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Tabs value={selectedTab} onValueChange={setSelectedTab}>
|
|
||||||
<TabList>
|
|
||||||
{tabs.map((tab) => (
|
|
||||||
<Tab value={tab.key} key={tab.key}>
|
|
||||||
{tab.name}
|
|
||||||
</Tab>
|
|
||||||
))}
|
|
||||||
</TabList>
|
|
||||||
{tabs.map(({ key, component: Component }) => (
|
|
||||||
<TabPanel value={key} key={`tab-panel-${key}`}>
|
|
||||||
<Component />
|
|
||||||
</TabPanel>
|
|
||||||
))}
|
|
||||||
</Tabs>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1 +0,0 @@
|
|||||||
export { SsoTabGroup } from "./SsoTabGroup";
|
|
@ -1,26 +0,0 @@
|
|||||||
import { createFileRoute, stripSearchParams } from "@tanstack/react-router";
|
|
||||||
import { zodValidator } from "@tanstack/zod-adapter";
|
|
||||||
import { z } from "zod";
|
|
||||||
|
|
||||||
import { SsoPage } from "./SsoPage";
|
|
||||||
|
|
||||||
const SettingsPageQueryParams = z.object({
|
|
||||||
selectedTab: z.string().catch("")
|
|
||||||
});
|
|
||||||
|
|
||||||
export const Route = createFileRoute(
|
|
||||||
"/_authenticate/_inject-org-details/_org-layout/organization/sso"
|
|
||||||
)({
|
|
||||||
component: SsoPage,
|
|
||||||
validateSearch: zodValidator(SettingsPageQueryParams),
|
|
||||||
search: {
|
|
||||||
middlewares: [stripSearchParams({ selectedTab: "" })]
|
|
||||||
},
|
|
||||||
context: () => ({
|
|
||||||
breadcrumbs: [
|
|
||||||
{
|
|
||||||
label: "Single Sign-On (SSO)"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
});
|
|
@ -55,7 +55,7 @@ const formSchema = z
|
|||||||
.object({
|
.object({
|
||||||
environment: z.object({ slug: z.string(), name: z.string() }),
|
environment: z.object({ slug: z.string(), name: z.string() }),
|
||||||
name: z.string().optional(),
|
name: z.string().optional(),
|
||||||
secretPath: z.string().optional(),
|
secretPath: z.string().trim().min(1),
|
||||||
approvals: z.number().min(1).default(1),
|
approvals: z.number().min(1).default(1),
|
||||||
userApprovers: z
|
userApprovers: z
|
||||||
.object({ type: z.literal(ApproverType.User), id: z.string() })
|
.object({ type: z.literal(ApproverType.User), id: z.string() })
|
||||||
@ -93,10 +93,8 @@ const formSchema = z
|
|||||||
.optional()
|
.optional()
|
||||||
})
|
})
|
||||||
.superRefine((data, ctx) => {
|
.superRefine((data, ctx) => {
|
||||||
if (
|
if (data.policyType === PolicyType.ChangePolicy) {
|
||||||
data.policyType === PolicyType.ChangePolicy &&
|
if (!(data.groupApprovers.length || data.userApprovers.length)) {
|
||||||
!(data.groupApprovers.length || data.userApprovers.length)
|
|
||||||
) {
|
|
||||||
ctx.addIssue({
|
ctx.addIssue({
|
||||||
path: ["userApprovers"],
|
path: ["userApprovers"],
|
||||||
code: z.ZodIssueCode.custom,
|
code: z.ZodIssueCode.custom,
|
||||||
@ -108,6 +106,7 @@ const formSchema = z
|
|||||||
message: "At least one approver should be provided"
|
message: "At least one approver should be provided"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
type TFormSchema = z.infer<typeof formSchema>;
|
type TFormSchema = z.infer<typeof formSchema>;
|
||||||
@ -127,6 +126,7 @@ const Form = ({
|
|||||||
control,
|
control,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
watch,
|
watch,
|
||||||
|
resetField,
|
||||||
formState: { isSubmitting }
|
formState: { isSubmitting }
|
||||||
} = useForm<TFormSchema>({
|
} = useForm<TFormSchema>({
|
||||||
resolver: zodResolver(formSchema),
|
resolver: zodResolver(formSchema),
|
||||||
@ -177,6 +177,7 @@ const Form = ({
|
|||||||
: undefined,
|
: undefined,
|
||||||
defaultValues: !editValues
|
defaultValues: !editValues
|
||||||
? {
|
? {
|
||||||
|
secretPath: "/",
|
||||||
sequenceApprovers: [{ approvals: 1 }]
|
sequenceApprovers: [{ approvals: 1 }]
|
||||||
}
|
}
|
||||||
: undefined
|
: undefined
|
||||||
@ -405,7 +406,10 @@ const Form = ({
|
|||||||
<Select
|
<Select
|
||||||
isDisabled={isEditMode}
|
isDisabled={isEditMode}
|
||||||
value={value}
|
value={value}
|
||||||
onValueChange={(val) => onChange(val as PolicyType)}
|
onValueChange={(val) => {
|
||||||
|
onChange(val as PolicyType);
|
||||||
|
resetField("secretPath");
|
||||||
|
}}
|
||||||
className="w-full border border-mineshaft-500"
|
className="w-full border border-mineshaft-500"
|
||||||
>
|
>
|
||||||
{Object.values(PolicyType).map((policyType) => {
|
{Object.values(PolicyType).map((policyType) => {
|
||||||
@ -465,6 +469,7 @@ const Form = ({
|
|||||||
<FormControl
|
<FormControl
|
||||||
tooltipText="Secret paths support glob patterns. For example, '/**' will match all paths."
|
tooltipText="Secret paths support glob patterns. For example, '/**' will match all paths."
|
||||||
label="Secret Path"
|
label="Secret Path"
|
||||||
|
isRequired
|
||||||
isError={Boolean(error)}
|
isError={Boolean(error)}
|
||||||
errorText={error?.message}
|
errorText={error?.message}
|
||||||
className="flex-1"
|
className="flex-1"
|
||||||
|
@ -338,8 +338,14 @@ export const SecretApprovalRequest = () => {
|
|||||||
</div>
|
</div>
|
||||||
<span className="text-xs leading-3 text-gray-500">
|
<span className="text-xs leading-3 text-gray-500">
|
||||||
Opened {formatDistance(new Date(createdAt), new Date())} ago by{" "}
|
Opened {formatDistance(new Date(createdAt), new Date())} ago by{" "}
|
||||||
|
{committerUser ? (
|
||||||
|
<>
|
||||||
{committerUser?.firstName || ""} {committerUser?.lastName || ""} (
|
{committerUser?.firstName || ""} {committerUser?.lastName || ""} (
|
||||||
{committerUser?.email})
|
{committerUser?.email})
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<span className="text-gray-600">Deleted User</span>
|
||||||
|
)}
|
||||||
{!isReviewed && status === "open" && " - Review required"}
|
{!isReviewed && status === "open" && " - Review required"}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -250,10 +250,17 @@ export const SecretApprovalRequestChanges = ({
|
|||||||
secretApprovalRequestDetails.isReplicated
|
secretApprovalRequestDetails.isReplicated
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<span className="-mt-1 flex items-center space-x-2 text-xs text-gray-400">
|
<p className="-mt-1 text-xs text-gray-400">
|
||||||
By {secretApprovalRequestDetails?.committerUser?.firstName} (
|
By{" "}
|
||||||
|
{secretApprovalRequestDetails?.committerUser ? (
|
||||||
|
<>
|
||||||
|
{secretApprovalRequestDetails?.committerUser?.firstName} (
|
||||||
{secretApprovalRequestDetails?.committerUser?.email})
|
{secretApprovalRequestDetails?.committerUser?.email})
|
||||||
</span>
|
</>
|
||||||
|
) : (
|
||||||
|
<span className="text-gray-500">Deleted User</span>
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
{!hasMerged &&
|
{!hasMerged &&
|
||||||
secretApprovalRequestDetails.status === "open" &&
|
secretApprovalRequestDetails.status === "open" &&
|
||||||
|
@ -47,7 +47,6 @@ import { Route as adminEnvironmentPageRouteImport } from './pages/admin/Environm
|
|||||||
import { Route as adminEncryptionPageRouteImport } from './pages/admin/EncryptionPage/route'
|
import { Route as adminEncryptionPageRouteImport } from './pages/admin/EncryptionPage/route'
|
||||||
import { Route as adminCachingPageRouteImport } from './pages/admin/CachingPage/route'
|
import { Route as adminCachingPageRouteImport } from './pages/admin/CachingPage/route'
|
||||||
import { Route as adminAuthenticationPageRouteImport } from './pages/admin/AuthenticationPage/route'
|
import { Route as adminAuthenticationPageRouteImport } from './pages/admin/AuthenticationPage/route'
|
||||||
import { Route as organizationSsoPageRouteImport } from './pages/organization/SsoPage/route'
|
|
||||||
import { Route as organizationProjectsPageRouteImport } from './pages/organization/ProjectsPage/route'
|
import { Route as organizationProjectsPageRouteImport } from './pages/organization/ProjectsPage/route'
|
||||||
import { Route as organizationBillingPageRouteImport } from './pages/organization/BillingPage/route'
|
import { Route as organizationBillingPageRouteImport } from './pages/organization/BillingPage/route'
|
||||||
import { Route as organizationAuditLogsPageRouteImport } from './pages/organization/AuditLogsPage/route'
|
import { Route as organizationAuditLogsPageRouteImport } from './pages/organization/AuditLogsPage/route'
|
||||||
@ -591,12 +590,6 @@ const adminAuthenticationPageRouteRoute =
|
|||||||
getParentRoute: () => adminLayoutRoute,
|
getParentRoute: () => adminLayoutRoute,
|
||||||
} as any)
|
} as any)
|
||||||
|
|
||||||
const organizationSsoPageRouteRoute = organizationSsoPageRouteImport.update({
|
|
||||||
id: '/sso',
|
|
||||||
path: '/sso',
|
|
||||||
getParentRoute: () => AuthenticateInjectOrgDetailsOrgLayoutOrganizationRoute,
|
|
||||||
} as any)
|
|
||||||
|
|
||||||
const organizationProjectsPageRouteRoute =
|
const organizationProjectsPageRouteRoute =
|
||||||
organizationProjectsPageRouteImport.update({
|
organizationProjectsPageRouteImport.update({
|
||||||
id: '/projects',
|
id: '/projects',
|
||||||
@ -2159,13 +2152,6 @@ declare module '@tanstack/react-router' {
|
|||||||
preLoaderRoute: typeof organizationProjectsPageRouteImport
|
preLoaderRoute: typeof organizationProjectsPageRouteImport
|
||||||
parentRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationImport
|
parentRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationImport
|
||||||
}
|
}
|
||||||
'/_authenticate/_inject-org-details/_org-layout/organization/sso': {
|
|
||||||
id: '/_authenticate/_inject-org-details/_org-layout/organization/sso'
|
|
||||||
path: '/sso'
|
|
||||||
fullPath: '/organization/sso'
|
|
||||||
preLoaderRoute: typeof organizationSsoPageRouteImport
|
|
||||||
parentRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationImport
|
|
||||||
}
|
|
||||||
'/_authenticate/_inject-org-details/admin/_admin-layout/authentication': {
|
'/_authenticate/_inject-org-details/admin/_admin-layout/authentication': {
|
||||||
id: '/_authenticate/_inject-org-details/admin/_admin-layout/authentication'
|
id: '/_authenticate/_inject-org-details/admin/_admin-layout/authentication'
|
||||||
path: '/authentication'
|
path: '/authentication'
|
||||||
@ -3428,7 +3414,6 @@ interface AuthenticateInjectOrgDetailsOrgLayoutOrganizationRouteChildren {
|
|||||||
organizationAuditLogsPageRouteRoute: typeof organizationAuditLogsPageRouteRoute
|
organizationAuditLogsPageRouteRoute: typeof organizationAuditLogsPageRouteRoute
|
||||||
organizationBillingPageRouteRoute: typeof organizationBillingPageRouteRoute
|
organizationBillingPageRouteRoute: typeof organizationBillingPageRouteRoute
|
||||||
organizationProjectsPageRouteRoute: typeof organizationProjectsPageRouteRoute
|
organizationProjectsPageRouteRoute: typeof organizationProjectsPageRouteRoute
|
||||||
organizationSsoPageRouteRoute: typeof organizationSsoPageRouteRoute
|
|
||||||
AuthenticateInjectOrgDetailsOrgLayoutOrganizationAppConnectionsRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationAppConnectionsRouteWithChildren
|
AuthenticateInjectOrgDetailsOrgLayoutOrganizationAppConnectionsRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationAppConnectionsRouteWithChildren
|
||||||
AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysRouteWithChildren
|
AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysRouteWithChildren
|
||||||
AuthenticateInjectOrgDetailsOrgLayoutOrganizationSecretSharingRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationSecretSharingRouteWithChildren
|
AuthenticateInjectOrgDetailsOrgLayoutOrganizationSecretSharingRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationSecretSharingRouteWithChildren
|
||||||
@ -3447,7 +3432,6 @@ const AuthenticateInjectOrgDetailsOrgLayoutOrganizationRouteChildren: Authentica
|
|||||||
organizationAuditLogsPageRouteRoute: organizationAuditLogsPageRouteRoute,
|
organizationAuditLogsPageRouteRoute: organizationAuditLogsPageRouteRoute,
|
||||||
organizationBillingPageRouteRoute: organizationBillingPageRouteRoute,
|
organizationBillingPageRouteRoute: organizationBillingPageRouteRoute,
|
||||||
organizationProjectsPageRouteRoute: organizationProjectsPageRouteRoute,
|
organizationProjectsPageRouteRoute: organizationProjectsPageRouteRoute,
|
||||||
organizationSsoPageRouteRoute: organizationSsoPageRouteRoute,
|
|
||||||
AuthenticateInjectOrgDetailsOrgLayoutOrganizationAppConnectionsRoute:
|
AuthenticateInjectOrgDetailsOrgLayoutOrganizationAppConnectionsRoute:
|
||||||
AuthenticateInjectOrgDetailsOrgLayoutOrganizationAppConnectionsRouteWithChildren,
|
AuthenticateInjectOrgDetailsOrgLayoutOrganizationAppConnectionsRouteWithChildren,
|
||||||
AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysRoute:
|
AuthenticateInjectOrgDetailsOrgLayoutOrganizationGatewaysRoute:
|
||||||
@ -4345,7 +4329,6 @@ export interface FileRoutesByFullPath {
|
|||||||
'/organization/audit-logs': typeof organizationAuditLogsPageRouteRoute
|
'/organization/audit-logs': typeof organizationAuditLogsPageRouteRoute
|
||||||
'/organization/billing': typeof organizationBillingPageRouteRoute
|
'/organization/billing': typeof organizationBillingPageRouteRoute
|
||||||
'/organization/projects': typeof organizationProjectsPageRouteRoute
|
'/organization/projects': typeof organizationProjectsPageRouteRoute
|
||||||
'/organization/sso': typeof organizationSsoPageRouteRoute
|
|
||||||
'/admin/authentication': typeof adminAuthenticationPageRouteRoute
|
'/admin/authentication': typeof adminAuthenticationPageRouteRoute
|
||||||
'/admin/caching': typeof adminCachingPageRouteRoute
|
'/admin/caching': typeof adminCachingPageRouteRoute
|
||||||
'/admin/encryption': typeof adminEncryptionPageRouteRoute
|
'/admin/encryption': typeof adminEncryptionPageRouteRoute
|
||||||
@ -4542,7 +4525,6 @@ export interface FileRoutesByTo {
|
|||||||
'/organization/audit-logs': typeof organizationAuditLogsPageRouteRoute
|
'/organization/audit-logs': typeof organizationAuditLogsPageRouteRoute
|
||||||
'/organization/billing': typeof organizationBillingPageRouteRoute
|
'/organization/billing': typeof organizationBillingPageRouteRoute
|
||||||
'/organization/projects': typeof organizationProjectsPageRouteRoute
|
'/organization/projects': typeof organizationProjectsPageRouteRoute
|
||||||
'/organization/sso': typeof organizationSsoPageRouteRoute
|
|
||||||
'/admin/authentication': typeof adminAuthenticationPageRouteRoute
|
'/admin/authentication': typeof adminAuthenticationPageRouteRoute
|
||||||
'/admin/caching': typeof adminCachingPageRouteRoute
|
'/admin/caching': typeof adminCachingPageRouteRoute
|
||||||
'/admin/encryption': typeof adminEncryptionPageRouteRoute
|
'/admin/encryption': typeof adminEncryptionPageRouteRoute
|
||||||
@ -4739,7 +4721,6 @@ export interface FileRoutesById {
|
|||||||
'/_authenticate/_inject-org-details/_org-layout/organization/audit-logs': typeof organizationAuditLogsPageRouteRoute
|
'/_authenticate/_inject-org-details/_org-layout/organization/audit-logs': typeof organizationAuditLogsPageRouteRoute
|
||||||
'/_authenticate/_inject-org-details/_org-layout/organization/billing': typeof organizationBillingPageRouteRoute
|
'/_authenticate/_inject-org-details/_org-layout/organization/billing': typeof organizationBillingPageRouteRoute
|
||||||
'/_authenticate/_inject-org-details/_org-layout/organization/projects': typeof organizationProjectsPageRouteRoute
|
'/_authenticate/_inject-org-details/_org-layout/organization/projects': typeof organizationProjectsPageRouteRoute
|
||||||
'/_authenticate/_inject-org-details/_org-layout/organization/sso': typeof organizationSsoPageRouteRoute
|
|
||||||
'/_authenticate/_inject-org-details/admin/_admin-layout/authentication': typeof adminAuthenticationPageRouteRoute
|
'/_authenticate/_inject-org-details/admin/_admin-layout/authentication': typeof adminAuthenticationPageRouteRoute
|
||||||
'/_authenticate/_inject-org-details/admin/_admin-layout/caching': typeof adminCachingPageRouteRoute
|
'/_authenticate/_inject-org-details/admin/_admin-layout/caching': typeof adminCachingPageRouteRoute
|
||||||
'/_authenticate/_inject-org-details/admin/_admin-layout/encryption': typeof adminEncryptionPageRouteRoute
|
'/_authenticate/_inject-org-details/admin/_admin-layout/encryption': typeof adminEncryptionPageRouteRoute
|
||||||
@ -4949,7 +4930,6 @@ export interface FileRouteTypes {
|
|||||||
| '/organization/audit-logs'
|
| '/organization/audit-logs'
|
||||||
| '/organization/billing'
|
| '/organization/billing'
|
||||||
| '/organization/projects'
|
| '/organization/projects'
|
||||||
| '/organization/sso'
|
|
||||||
| '/admin/authentication'
|
| '/admin/authentication'
|
||||||
| '/admin/caching'
|
| '/admin/caching'
|
||||||
| '/admin/encryption'
|
| '/admin/encryption'
|
||||||
@ -5145,7 +5125,6 @@ export interface FileRouteTypes {
|
|||||||
| '/organization/audit-logs'
|
| '/organization/audit-logs'
|
||||||
| '/organization/billing'
|
| '/organization/billing'
|
||||||
| '/organization/projects'
|
| '/organization/projects'
|
||||||
| '/organization/sso'
|
|
||||||
| '/admin/authentication'
|
| '/admin/authentication'
|
||||||
| '/admin/caching'
|
| '/admin/caching'
|
||||||
| '/admin/encryption'
|
| '/admin/encryption'
|
||||||
@ -5340,7 +5319,6 @@ export interface FileRouteTypes {
|
|||||||
| '/_authenticate/_inject-org-details/_org-layout/organization/audit-logs'
|
| '/_authenticate/_inject-org-details/_org-layout/organization/audit-logs'
|
||||||
| '/_authenticate/_inject-org-details/_org-layout/organization/billing'
|
| '/_authenticate/_inject-org-details/_org-layout/organization/billing'
|
||||||
| '/_authenticate/_inject-org-details/_org-layout/organization/projects'
|
| '/_authenticate/_inject-org-details/_org-layout/organization/projects'
|
||||||
| '/_authenticate/_inject-org-details/_org-layout/organization/sso'
|
|
||||||
| '/_authenticate/_inject-org-details/admin/_admin-layout/authentication'
|
| '/_authenticate/_inject-org-details/admin/_admin-layout/authentication'
|
||||||
| '/_authenticate/_inject-org-details/admin/_admin-layout/caching'
|
| '/_authenticate/_inject-org-details/admin/_admin-layout/caching'
|
||||||
| '/_authenticate/_inject-org-details/admin/_admin-layout/encryption'
|
| '/_authenticate/_inject-org-details/admin/_admin-layout/encryption'
|
||||||
@ -5732,7 +5710,6 @@ export const routeTree = rootRoute
|
|||||||
"/_authenticate/_inject-org-details/_org-layout/organization/audit-logs",
|
"/_authenticate/_inject-org-details/_org-layout/organization/audit-logs",
|
||||||
"/_authenticate/_inject-org-details/_org-layout/organization/billing",
|
"/_authenticate/_inject-org-details/_org-layout/organization/billing",
|
||||||
"/_authenticate/_inject-org-details/_org-layout/organization/projects",
|
"/_authenticate/_inject-org-details/_org-layout/organization/projects",
|
||||||
"/_authenticate/_inject-org-details/_org-layout/organization/sso",
|
|
||||||
"/_authenticate/_inject-org-details/_org-layout/organization/app-connections",
|
"/_authenticate/_inject-org-details/_org-layout/organization/app-connections",
|
||||||
"/_authenticate/_inject-org-details/_org-layout/organization/gateways",
|
"/_authenticate/_inject-org-details/_org-layout/organization/gateways",
|
||||||
"/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing",
|
"/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing",
|
||||||
@ -5782,10 +5759,6 @@ export const routeTree = rootRoute
|
|||||||
"filePath": "organization/ProjectsPage/route.tsx",
|
"filePath": "organization/ProjectsPage/route.tsx",
|
||||||
"parent": "/_authenticate/_inject-org-details/_org-layout/organization"
|
"parent": "/_authenticate/_inject-org-details/_org-layout/organization"
|
||||||
},
|
},
|
||||||
"/_authenticate/_inject-org-details/_org-layout/organization/sso": {
|
|
||||||
"filePath": "organization/SsoPage/route.tsx",
|
|
||||||
"parent": "/_authenticate/_inject-org-details/_org-layout/organization"
|
|
||||||
},
|
|
||||||
"/_authenticate/_inject-org-details/admin/_admin-layout/authentication": {
|
"/_authenticate/_inject-org-details/admin/_admin-layout/authentication": {
|
||||||
"filePath": "admin/AuthenticationPage/route.tsx",
|
"filePath": "admin/AuthenticationPage/route.tsx",
|
||||||
"parent": "/_authenticate/_inject-org-details/admin/_admin-layout"
|
"parent": "/_authenticate/_inject-org-details/admin/_admin-layout"
|
||||||
|
@ -31,7 +31,6 @@ const organizationRoutes = route("/organization", [
|
|||||||
index("organization/SettingsPage/route.tsx"),
|
index("organization/SettingsPage/route.tsx"),
|
||||||
route("/oauth/callback", "organization/SettingsPage/OauthCallbackPage/route.tsx")
|
route("/oauth/callback", "organization/SettingsPage/OauthCallbackPage/route.tsx")
|
||||||
]),
|
]),
|
||||||
route("/sso", "organization/SsoPage/route.tsx"),
|
|
||||||
route("/groups/$groupId", "organization/GroupDetailsByIDPage/route.tsx"),
|
route("/groups/$groupId", "organization/GroupDetailsByIDPage/route.tsx"),
|
||||||
route("/members/$membershipId", "organization/UserDetailsByIDPage/route.tsx"),
|
route("/members/$membershipId", "organization/UserDetailsByIDPage/route.tsx"),
|
||||||
route("/roles/$roleId", "organization/RoleByIDPage/route.tsx"),
|
route("/roles/$roleId", "organization/RoleByIDPage/route.tsx"),
|
||||||
|
Reference in New Issue
Block a user