Merge branch 'heads/main' into daniel/hsm-improvements-prep-work

This commit is contained in:
Daniel Hougaard
2025-10-22 15:11:39 +04:00
200 changed files with 5621 additions and 2275 deletions
@@ -0,0 +1,66 @@
import { Knex } from "knex";
import { dropConstraintIfExists } from "@app/db/migrations/utils/dropConstraintIfExists";
import { AccessScope, TableName } from "../schemas";
export async function up(knex: Knex): Promise<void> {
const hasParentOrgId = await knex.schema.hasColumn(TableName.Organization, "parentOrgId");
if (!hasParentOrgId) {
await knex.schema.alterTable(TableName.Organization, async (t) => {
// the one just above the chain
t.uuid("parentOrgId");
t.foreign("parentOrgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
// this would root organization containing various informations like billing etc
t.uuid("rootOrgId");
t.foreign("rootOrgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
await dropConstraintIfExists(TableName.Organization, "organizations_slug_unique", knex);
t.unique(["rootOrgId", "parentOrgId", "slug"]);
});
// had to switch to raw for null not distinct
}
const hasIdentityOrgCol = await knex.schema.hasColumn(TableName.Identity, "orgId");
if (!hasIdentityOrgCol) {
await knex.schema.alterTable(TableName.Identity, (t) => {
t.uuid("orgId");
t.foreign("orgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
});
await knex.raw(
`
UPDATE ?? AS identity
SET "orgId" = membership."scopeOrgId"
FROM ?? AS membership
WHERE
membership."actorIdentityId" = identity."id"
AND membership."scope" = ?
`,
[TableName.Identity, TableName.Membership, AccessScope.Organization]
);
await knex.schema.alterTable(TableName.Identity, (t) => {
t.uuid("orgId").notNullable().alter();
});
}
}
export async function down(knex: Knex): Promise<void> {
const hasParentOrgId = await knex.schema.hasColumn(TableName.Organization, "parentOrgId");
const hasRootOrgId = await knex.schema.hasColumn(TableName.Organization, "rootOrgId");
if (hasParentOrgId || hasRootOrgId) {
await knex.schema.alterTable(TableName.Organization, (t) => {
if (hasParentOrgId) t.dropColumn("parentOrgId");
if (hasRootOrgId) t.dropColumn("rootOrgId");
});
}
const hasIdentityOrgCol = await knex.schema.hasColumn(TableName.Identity, "orgId");
if (hasIdentityOrgCol) {
await knex.schema.alterTable(TableName.Identity, (t) => {
t.dropColumn("orgId");
});
}
}
+2 -1
View File
@@ -13,7 +13,8 @@ export const IdentitiesSchema = z.object({
authMethod: z.string().nullable().optional(),
createdAt: z.date(),
updatedAt: z.date(),
hasDeleteProtection: z.boolean().default(false)
hasDeleteProtection: z.boolean().default(false),
orgId: z.string().uuid()
});
export type TIdentities = z.infer<typeof IdentitiesSchema>;
+6
View File
@@ -316,6 +316,12 @@ export enum ActionProjectType {
Any = "any"
}
export enum OrganizationActionScope {
ChildOrganization = "child-organization-only",
ParentOrganization = "parent-organization-only",
Any = "any"
}
export enum TemporaryPermissionMode {
Relative = "relative"
}
+3 -1
View File
@@ -38,7 +38,9 @@ export const OrganizationsSchema = z.object({
maxSharedSecretLifetime: z.number().default(2592000).nullable().optional(),
maxSharedSecretViewLimit: z.number().nullable().optional(),
googleSsoAuthEnforced: z.boolean().default(false),
googleSsoAuthLastUsed: z.date().nullable().optional()
googleSsoAuthLastUsed: z.date().nullable().optional(),
parentOrgId: z.string().uuid().nullable().optional(),
rootOrgId: z.string().uuid().nullable().optional()
});
export type TOrganizations = z.infer<typeof OrganizationsSchema>;
+2 -1
View File
@@ -40,7 +40,8 @@ export async function seed(knex: Knex): Promise<void> {
// @ts-ignore
id: seedData1.machineIdentity.id,
name: seedData1.machineIdentity.name,
authMethod: IdentityAuthMethod.UNIVERSAL_AUTH
authMethod: IdentityAuthMethod.UNIVERSAL_AUTH,
orgId: seedData1.organization.id
}
]);
const identityUa = await knex(TableName.IdentityUniversalAuth)