mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
feat: added migration for new memberships
This commit is contained in:
29
backend/src/@types/knex.d.ts
vendored
29
backend/src/@types/knex.d.ts
vendored
@@ -17,6 +17,9 @@ import {
|
||||
TAccessApprovalRequestsReviewersInsert,
|
||||
TAccessApprovalRequestsReviewersUpdate,
|
||||
TAccessApprovalRequestsUpdate,
|
||||
TAdditionalPrivileges,
|
||||
TAdditionalPrivilegesInsert,
|
||||
TAdditionalPrivilegesUpdate,
|
||||
TApiKeys,
|
||||
TApiKeysInsert,
|
||||
TApiKeysUpdate,
|
||||
@@ -227,6 +230,15 @@ import {
|
||||
TLdapGroupMaps,
|
||||
TLdapGroupMapsInsert,
|
||||
TLdapGroupMapsUpdate,
|
||||
TMembershipRoles,
|
||||
TMembershipRolesInsert,
|
||||
TMembershipRolesUpdate,
|
||||
TMemberships,
|
||||
TMembershipsInsert,
|
||||
TMembershipsUpdate,
|
||||
TNamespaces,
|
||||
TNamespacesInsert,
|
||||
TNamespacesUpdate,
|
||||
TOidcConfigs,
|
||||
TOidcConfigsInsert,
|
||||
TOidcConfigsUpdate,
|
||||
@@ -314,6 +326,9 @@ import {
|
||||
TResourceMetadata,
|
||||
TResourceMetadataInsert,
|
||||
TResourceMetadataUpdate,
|
||||
TRoles,
|
||||
TRolesInsert,
|
||||
TRolesUpdate,
|
||||
TSamlConfigs,
|
||||
TSamlConfigsInsert,
|
||||
TSamlConfigsUpdate,
|
||||
@@ -1316,5 +1331,19 @@ declare module "knex/types/tables" {
|
||||
[TableName.PamResource]: KnexOriginal.CompositeTableType<TPamResources, TPamResourcesInsert, TPamResourcesUpdate>;
|
||||
[TableName.PamAccount]: KnexOriginal.CompositeTableType<TPamAccounts, TPamAccountsInsert, TPamAccountsUpdate>;
|
||||
[TableName.PamSession]: KnexOriginal.CompositeTableType<TPamSessions, TPamSessionsInsert, TPamSessionsUpdate>;
|
||||
|
||||
[TableName.Namespace]: KnexOriginal.CompositeTableType<TNamespaces, TNamespacesInsert, TNamespacesUpdate>;
|
||||
[TableName.Membership]: KnexOriginal.CompositeTableType<TMemberships, TMembershipsInsert, TMembershipsUpdate>;
|
||||
[TableName.MembershipRoles]: KnexOriginal.CompositeTableType<
|
||||
TMembershipRoles,
|
||||
TMembershipRolesInsert,
|
||||
TMembershipRolesUpdate
|
||||
>;
|
||||
[TableName.Roles]: KnexOriginal.CompositeTableType<TRoles, TRolesInsert, TRolesUpdate>;
|
||||
[TableName.AdditionalPrivilege]: KnexOriginal.CompositeTableType<
|
||||
TAdditionalPrivileges,
|
||||
TAdditionalPrivilegesInsert,
|
||||
TAdditionalPrivilegesUpdate
|
||||
>;
|
||||
}
|
||||
}
|
||||
|
||||
166
backend/src/db/migrations/20250925145952_simplify-membership.ts
Normal file
166
backend/src/db/migrations/20250925145952_simplify-membership.ts
Normal file
@@ -0,0 +1,166 @@
|
||||
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.Namespace))) {
|
||||
await knex.schema.createTable(TableName.Namespace, (t) => {
|
||||
t.uuid("id").primary().defaultTo(knex.fn.uuid());
|
||||
t.string("name").notNullable();
|
||||
t.string("description");
|
||||
t.uuid("orgId").notNullable();
|
||||
t.foreign("orgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
|
||||
t.timestamps(true, true, true);
|
||||
});
|
||||
|
||||
await createOnUpdateTrigger(knex, TableName.Namespace);
|
||||
}
|
||||
|
||||
if (!(await knex.schema.hasTable(TableName.Membership))) {
|
||||
await knex.schema.createTable(TableName.Membership, (t) => {
|
||||
t.uuid("id").primary().defaultTo(knex.fn.uuid());
|
||||
t.string("scope", 24).notNullable();
|
||||
|
||||
t.uuid("actorUserId");
|
||||
t.foreign("actorUserId").references("id").inTable(TableName.Users).onDelete("CASCADE");
|
||||
t.uuid("actorIdentityId");
|
||||
t.foreign("actorIdentityId").references("id").inTable(TableName.Identity).onDelete("CASCADE");
|
||||
t.uuid("actorGroupId");
|
||||
t.foreign("actorGroupId").references("id").inTable(TableName.Groups).onDelete("CASCADE");
|
||||
|
||||
t.uuid("scopeOrgId").notNullable();
|
||||
t.foreign("scopeOrgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
|
||||
t.string("scopeProjectId", 36);
|
||||
t.foreign("scopeProjectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
||||
t.uuid("scopeNamespaceId");
|
||||
t.foreign("scopeNamespaceId").references("id").inTable(TableName.Namespace).onDelete("CASCADE");
|
||||
|
||||
t.boolean("isActive");
|
||||
t.string("status").defaultTo("invited");
|
||||
t.string("inviteEmail");
|
||||
t.datetime("lastInvitedAt");
|
||||
t.datetime("lastLoginAuthMethod");
|
||||
t.datetime("lastLoginTime");
|
||||
t.specificType("projectFavorites", "text[]");
|
||||
t.timestamps(true, true, true);
|
||||
|
||||
t.check(
|
||||
`(:actorUserIdColumn: IS NOT NULL AND :actorIdentityIdColumn: IS NULL AND :actorGroupIdColumn: IS NULL) OR
|
||||
(:actorIdentityIdColumn: IS NOT NULL AND :actorUserIdColumn: IS NULL AND :actorGroupIdColumn: IS NULL) OR
|
||||
(:actorGroupIdColumn: IS NOT NULL AND :actorUserIdColumn: IS NULL AND :actorIdentityIdColumn: IS NULL)`,
|
||||
{
|
||||
actorUserIdColumn: "actorUserId",
|
||||
actorIdentityIdColumn: "actorIdentityId",
|
||||
actorGroupIdColumn: "actorGroupId"
|
||||
},
|
||||
"only_one_actor_type"
|
||||
);
|
||||
|
||||
t.check(
|
||||
`(:scopeColumn: = 'namespace' AND :scopeNamespaceIdColumn: IS NOT NULL) OR
|
||||
(:scopeColumn: = 'project' AND :scopeProjectIdColumn: IS NOT NULL) OR
|
||||
(:scopeColumn: = 'organization')
|
||||
`,
|
||||
{
|
||||
scopeColumn: "scope",
|
||||
scopeNamespaceIdColumn: "scopeNamespaceId",
|
||||
scopeProjectIdColumn: "scopeProjectId"
|
||||
},
|
||||
"scope_matches_id"
|
||||
);
|
||||
});
|
||||
|
||||
await createOnUpdateTrigger(knex, TableName.Membership);
|
||||
}
|
||||
|
||||
if (!(await knex.schema.hasTable(TableName.Role))) {
|
||||
await knex.schema.createTable(TableName.Role, (t) => {
|
||||
t.uuid("id").primary().defaultTo(knex.fn.uuid());
|
||||
t.string("name").notNullable();
|
||||
t.string("description");
|
||||
t.string("slug").notNullable();
|
||||
t.jsonb("permissions").notNullable();
|
||||
|
||||
t.uuid("orgId");
|
||||
t.foreign("orgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
|
||||
t.string("projectId", 36);
|
||||
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
||||
t.uuid("namespaceId");
|
||||
t.foreign("namespaceId").references("id").inTable(TableName.Namespace).onDelete("CASCADE");
|
||||
|
||||
t.check(
|
||||
`(:orgIdColumn: IS NOT NULL AND :namespaceIdColumn: IS NULL AND :projectIdColumn: IS NULL) OR
|
||||
(:namespaceIdColumn: IS NOT NULL AND :orgIdColumn: IS NULL AND :projectIdColumn: IS NULL) OR
|
||||
(:projectIdColumn: IS NOT NULL AND :orgIdColumn: IS NULL AND :namespaceIdColumn: IS NULL)`,
|
||||
{
|
||||
orgIdColumn: "orgId",
|
||||
namespaceIdColumn: "namespaceId",
|
||||
projectIdColumn: "projectId"
|
||||
},
|
||||
"only_one_scope_id"
|
||||
);
|
||||
|
||||
t.timestamps(true, true, true);
|
||||
});
|
||||
|
||||
await createOnUpdateTrigger(knex, TableName.Role);
|
||||
}
|
||||
|
||||
if (!(await knex.schema.hasTable(TableName.MembershipRole))) {
|
||||
await knex.schema.createTable(TableName.MembershipRole, (t) => {
|
||||
t.uuid("id").primary().defaultTo(knex.fn.uuid());
|
||||
t.string("role").notNullable();
|
||||
t.boolean("isTemporary").notNullable().defaultTo(false);
|
||||
t.string("temporaryMode");
|
||||
t.string("temporaryRange"); // could be cron or relative time like 1H or 1minute etc
|
||||
t.datetime("temporaryAccessStartTime");
|
||||
t.datetime("temporaryAccessEndTime");
|
||||
|
||||
t.uuid("customRoleId");
|
||||
t.foreign("customRoleId").references("id").inTable(TableName.Role);
|
||||
t.uuid("membershipId").notNullable();
|
||||
t.foreign("membershipId").references("id").inTable(TableName.Membership).onDelete("CASCADE");
|
||||
|
||||
t.timestamps(true, true, true);
|
||||
});
|
||||
|
||||
await createOnUpdateTrigger(knex, TableName.MembershipRole);
|
||||
}
|
||||
|
||||
if (!(await knex.schema.hasTable(TableName.AdditionalPrivilege))) {
|
||||
await knex.schema.createTable(TableName.AdditionalPrivilege, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.string("name", 60).notNullable();
|
||||
t.boolean("isTemporary").notNullable().defaultTo(false);
|
||||
t.string("temporaryMode");
|
||||
t.string("temporaryRange"); // could be cron or relative time like 1H or 1minute etc
|
||||
t.datetime("temporaryAccessStartTime");
|
||||
t.datetime("temporaryAccessEndTime");
|
||||
t.jsonb("permissions").notNullable();
|
||||
|
||||
t.uuid("membershipId").notNullable();
|
||||
t.foreign("membershipId").references("id").inTable(TableName.Membership).onDelete("CASCADE");
|
||||
t.timestamps(true, true, true);
|
||||
});
|
||||
|
||||
await createOnUpdateTrigger(knex, TableName.AdditionalPrivilege);
|
||||
}
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await dropOnUpdateTrigger(knex, TableName.AdditionalPrivilege);
|
||||
await knex.schema.dropTableIfExists(TableName.AdditionalPrivilege);
|
||||
|
||||
await dropOnUpdateTrigger(knex, TableName.MembershipRole);
|
||||
await knex.schema.dropTableIfExists(TableName.MembershipRole);
|
||||
|
||||
await dropOnUpdateTrigger(knex, TableName.Membership);
|
||||
await knex.schema.dropTableIfExists(TableName.Membership);
|
||||
|
||||
await dropOnUpdateTrigger(knex, TableName.Role);
|
||||
await knex.schema.dropTableIfExists(TableName.Role);
|
||||
|
||||
await dropOnUpdateTrigger(knex, TableName.Namespace);
|
||||
await knex.schema.dropTableIfExists(TableName.Namespace);
|
||||
}
|
||||
26
backend/src/db/schemas/additional-privileges.ts
Normal file
26
backend/src/db/schemas/additional-privileges.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
// 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 AdditionalPrivilegesSchema = z.object({
|
||||
id: z.string().uuid(),
|
||||
name: z.string(),
|
||||
isTemporary: z.boolean().default(false),
|
||||
temporaryMode: z.string().nullable().optional(),
|
||||
temporaryRange: z.string().nullable().optional(),
|
||||
temporaryAccessStartTime: z.date().nullable().optional(),
|
||||
temporaryAccessEndTime: z.date().nullable().optional(),
|
||||
permissions: z.unknown(),
|
||||
membershipId: z.string().uuid(),
|
||||
createdAt: z.date(),
|
||||
updatedAt: z.date()
|
||||
});
|
||||
|
||||
export type TAdditionalPrivileges = z.infer<typeof AdditionalPrivilegesSchema>;
|
||||
export type TAdditionalPrivilegesInsert = Omit<z.input<typeof AdditionalPrivilegesSchema>, TImmutableDBKeys>;
|
||||
export type TAdditionalPrivilegesUpdate = Partial<Omit<z.input<typeof AdditionalPrivilegesSchema>, TImmutableDBKeys>>;
|
||||
@@ -3,6 +3,7 @@ export * from "./access-approval-policies-approvers";
|
||||
export * from "./access-approval-policies-bypassers";
|
||||
export * from "./access-approval-requests";
|
||||
export * from "./access-approval-requests-reviewers";
|
||||
export * from "./additional-privileges";
|
||||
export * from "./api-keys";
|
||||
export * from "./app-connections";
|
||||
export * from "./audit-log-streams";
|
||||
@@ -73,8 +74,11 @@ export * from "./kms-keys";
|
||||
export * from "./kms-root-config";
|
||||
export * from "./ldap-configs";
|
||||
export * from "./ldap-group-maps";
|
||||
export * from "./membership-roles";
|
||||
export * from "./memberships";
|
||||
export * from "./microsoft-teams-integrations";
|
||||
export * from "./models";
|
||||
export * from "./namespaces";
|
||||
export * from "./oidc-configs";
|
||||
export * from "./org-bots";
|
||||
export * from "./org-gateway-config";
|
||||
@@ -108,6 +112,7 @@ export * from "./projects";
|
||||
export * from "./rate-limit";
|
||||
export * from "./relays";
|
||||
export * from "./resource-metadata";
|
||||
export * from "./roles";
|
||||
export * from "./saml-configs";
|
||||
export * from "./scim-tokens";
|
||||
export * from "./secret-approval-policies";
|
||||
|
||||
26
backend/src/db/schemas/membership-roles.ts
Normal file
26
backend/src/db/schemas/membership-roles.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
// 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 MembershipRolesSchema = z.object({
|
||||
id: z.string().uuid(),
|
||||
role: z.string(),
|
||||
isTemporary: z.boolean().default(false),
|
||||
temporaryMode: z.string().nullable().optional(),
|
||||
temporaryRange: z.string().nullable().optional(),
|
||||
temporaryAccessStartTime: z.date().nullable().optional(),
|
||||
temporaryAccessEndTime: z.date().nullable().optional(),
|
||||
customRoleId: z.string().uuid().nullable().optional(),
|
||||
membershipId: z.string().uuid(),
|
||||
createdAt: z.date(),
|
||||
updatedAt: z.date()
|
||||
});
|
||||
|
||||
export type TMembershipRoles = z.infer<typeof MembershipRolesSchema>;
|
||||
export type TMembershipRolesInsert = Omit<z.input<typeof MembershipRolesSchema>, TImmutableDBKeys>;
|
||||
export type TMembershipRolesUpdate = Partial<Omit<z.input<typeof MembershipRolesSchema>, TImmutableDBKeys>>;
|
||||
32
backend/src/db/schemas/memberships.ts
Normal file
32
backend/src/db/schemas/memberships.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
// 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 MembershipsSchema = z.object({
|
||||
id: z.string().uuid(),
|
||||
scope: z.string(),
|
||||
actorUserId: z.string().uuid().nullable().optional(),
|
||||
actorIdentityId: z.string().uuid().nullable().optional(),
|
||||
actorGroupId: z.string().uuid().nullable().optional(),
|
||||
scopeOrgId: z.string().uuid(),
|
||||
scopeProjectId: z.string().nullable().optional(),
|
||||
scopeNamespaceId: z.string().uuid().nullable().optional(),
|
||||
isActive: z.boolean().nullable().optional(),
|
||||
status: z.string().default("invited").nullable().optional(),
|
||||
inviteEmail: z.string().nullable().optional(),
|
||||
lastInvitedAt: z.date().nullable().optional(),
|
||||
lastLoginAuthMethod: z.date().nullable().optional(),
|
||||
lastLoginTime: z.date().nullable().optional(),
|
||||
projectFavorites: z.string().array().nullable().optional(),
|
||||
createdAt: z.date(),
|
||||
updatedAt: z.date()
|
||||
});
|
||||
|
||||
export type TMemberships = z.infer<typeof MembershipsSchema>;
|
||||
export type TMembershipsInsert = Omit<z.input<typeof MembershipsSchema>, TImmutableDBKeys>;
|
||||
export type TMembershipsUpdate = Partial<Omit<z.input<typeof MembershipsSchema>, TImmutableDBKeys>>;
|
||||
@@ -178,6 +178,14 @@ export enum TableName {
|
||||
SecretScanningScan = "secret_scanning_scans",
|
||||
SecretScanningFinding = "secret_scanning_findings",
|
||||
SecretScanningConfig = "secret_scanning_configs",
|
||||
|
||||
Membership = "memberships",
|
||||
MembershipRole = "membership_roles",
|
||||
Role = "roles",
|
||||
AdditionalPrivilege = "additional_privileges",
|
||||
|
||||
Namespace = "namespaces",
|
||||
|
||||
// reminders
|
||||
Reminder = "reminders",
|
||||
ReminderRecipient = "reminders_recipients",
|
||||
|
||||
21
backend/src/db/schemas/namespaces.ts
Normal file
21
backend/src/db/schemas/namespaces.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
// 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 NamespacesSchema = z.object({
|
||||
id: z.string().uuid(),
|
||||
name: z.string(),
|
||||
description: z.string().nullable().optional(),
|
||||
orgId: z.string().uuid(),
|
||||
createdAt: z.date(),
|
||||
updatedAt: z.date()
|
||||
});
|
||||
|
||||
export type TNamespaces = z.infer<typeof NamespacesSchema>;
|
||||
export type TNamespacesInsert = Omit<z.input<typeof NamespacesSchema>, TImmutableDBKeys>;
|
||||
export type TNamespacesUpdate = Partial<Omit<z.input<typeof NamespacesSchema>, TImmutableDBKeys>>;
|
||||
25
backend/src/db/schemas/roles.ts
Normal file
25
backend/src/db/schemas/roles.ts
Normal 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 RolesSchema = z.object({
|
||||
id: z.string().uuid(),
|
||||
name: z.string(),
|
||||
description: z.string().nullable().optional(),
|
||||
slug: z.string(),
|
||||
permissions: z.unknown(),
|
||||
orgId: z.string().uuid().nullable().optional(),
|
||||
projectId: z.string().nullable().optional(),
|
||||
namespaceId: z.string().uuid().nullable().optional(),
|
||||
createdAt: z.date(),
|
||||
updatedAt: z.date()
|
||||
});
|
||||
|
||||
export type TRoles = z.infer<typeof RolesSchema>;
|
||||
export type TRolesInsert = Omit<z.input<typeof RolesSchema>, TImmutableDBKeys>;
|
||||
export type TRolesUpdate = Partial<Omit<z.input<typeof RolesSchema>, TImmutableDBKeys>>;
|
||||
Reference in New Issue
Block a user