Merge remote-tracking branch 'origin/main' into feat/azurePkiConnector

This commit is contained in:
Carlos Monastyrski
2025-08-28 16:50:18 -03:00
151 changed files with 3300 additions and 1363 deletions
@@ -84,6 +84,9 @@ const up = async (knex: Knex): Promise<void> => {
t.index("expiresAt");
t.index("orgId");
t.index("projectId");
t.index("eventType");
t.index("userAgentType");
t.index("actor");
});
console.log("Adding GIN indices...");
@@ -119,8 +122,8 @@ const up = async (knex: Knex): Promise<void> => {
console.log("Creating audit log partitions ahead of time... next date:", nextDateStr);
await createAuditLogPartition(knex, nextDate, new Date(nextDate.getFullYear(), nextDate.getMonth() + 1));
// create partitions 4 years ahead
const partitionMonths = 4 * 12;
// create partitions 20 years ahead
const partitionMonths = 20 * 12;
const partitionPromises: Promise<void>[] = [];
for (let x = 1; x <= partitionMonths; x += 1) {
partitionPromises.push(
@@ -0,0 +1,49 @@
import { Knex } from "knex";
import { TableName } from "../schemas";
const BATCH_SIZE = 1000;
export async function up(knex: Knex): Promise<void> {
if (!(await knex.schema.hasColumn(TableName.UserAliases, "isEmailVerified"))) {
// Add the column
await knex.schema.alterTable(TableName.UserAliases, (t) => {
t.boolean("isEmailVerified").defaultTo(false);
});
const aliasesToUpdate: { aliasId: string; isEmailVerified: boolean }[] = await knex(TableName.UserAliases)
.join(TableName.Users, `${TableName.UserAliases}.userId`, `${TableName.Users}.id`)
.select([`${TableName.UserAliases}.id as aliasId`, `${TableName.Users}.isEmailVerified`]);
for (let i = 0; i < aliasesToUpdate.length; i += BATCH_SIZE) {
const batch = aliasesToUpdate.slice(i, i + BATCH_SIZE);
const trueIds = batch.filter((row) => row.isEmailVerified).map((row) => row.aliasId);
if (trueIds.length > 0) {
// eslint-disable-next-line no-await-in-loop
await knex(TableName.UserAliases).whereIn("id", trueIds).update({ isEmailVerified: true });
}
}
}
if (!(await knex.schema.hasColumn(TableName.AuthTokens, "aliasId"))) {
await knex.schema.alterTable(TableName.AuthTokens, (t) => {
t.string("aliasId").nullable();
});
}
}
export async function down(knex: Knex): Promise<void> {
if (await knex.schema.hasColumn(TableName.UserAliases, "isEmailVerified")) {
await knex.schema.alterTable(TableName.UserAliases, (t) => {
t.dropColumn("isEmailVerified");
});
}
if (await knex.schema.hasColumn(TableName.AuthTokens, "aliasId")) {
await knex.schema.alterTable(TableName.AuthTokens, (t) => {
t.dropColumn("aliasId");
});
}
}
@@ -0,0 +1,39 @@
import { Knex } from "knex";
import { TableName } from "../schemas";
const GOOGLE_SSO_AUTH_ENFORCED_COLUMN_NAME = "googleSsoAuthEnforced";
const GOOGLE_SSO_AUTH_LAST_USED_COLUMN_NAME = "googleSsoAuthLastUsed";
export async function up(knex: Knex): Promise<void> {
const hasGoogleSsoAuthEnforcedColumn = await knex.schema.hasColumn(
TableName.Organization,
GOOGLE_SSO_AUTH_ENFORCED_COLUMN_NAME
);
const hasGoogleSsoAuthLastUsedColumn = await knex.schema.hasColumn(
TableName.Organization,
GOOGLE_SSO_AUTH_LAST_USED_COLUMN_NAME
);
await knex.schema.alterTable(TableName.Organization, (table) => {
if (!hasGoogleSsoAuthEnforcedColumn)
table.boolean(GOOGLE_SSO_AUTH_ENFORCED_COLUMN_NAME).defaultTo(false).notNullable();
if (!hasGoogleSsoAuthLastUsedColumn) table.timestamp(GOOGLE_SSO_AUTH_LAST_USED_COLUMN_NAME).nullable();
});
}
export async function down(knex: Knex): Promise<void> {
const hasGoogleSsoAuthEnforcedColumn = await knex.schema.hasColumn(
TableName.Organization,
GOOGLE_SSO_AUTH_ENFORCED_COLUMN_NAME
);
const hasGoogleSsoAuthLastUsedColumn = await knex.schema.hasColumn(
TableName.Organization,
GOOGLE_SSO_AUTH_LAST_USED_COLUMN_NAME
);
await knex.schema.alterTable(TableName.Organization, (table) => {
if (hasGoogleSsoAuthEnforcedColumn) table.dropColumn(GOOGLE_SSO_AUTH_ENFORCED_COLUMN_NAME);
if (hasGoogleSsoAuthLastUsedColumn) table.dropColumn(GOOGLE_SSO_AUTH_LAST_USED_COLUMN_NAME);
});
}
@@ -0,0 +1,19 @@
import { Knex } from "knex";
import { TableName } from "../schemas";
export async function up(knex: Knex): Promise<void> {
if (!(await knex.schema.hasColumn(TableName.SecretApprovalPolicy, "shouldCheckSecretPermission"))) {
await knex.schema.alterTable(TableName.SecretApprovalPolicy, (t) => {
t.boolean("shouldCheckSecretPermission").nullable();
});
}
}
export async function down(knex: Knex): Promise<void> {
if (await knex.schema.hasColumn(TableName.SecretApprovalPolicy, "shouldCheckSecretPermission")) {
await knex.schema.alterTable(TableName.SecretApprovalPolicy, (t) => {
t.dropColumn("shouldCheckSecretPermission");
});
}
}
@@ -0,0 +1,29 @@
import { Knex } from "knex";
import { selectAllTableCols } from "@app/lib/knex";
import { TableName } from "../schemas";
const BATCH_SIZE = 100;
export async function up(knex: Knex): Promise<void> {
if (await knex.schema.hasColumn(TableName.SecretApprovalPolicy, "shouldCheckSecretPermission")) {
// find all existing SecretApprovalPolicy rows to backfill shouldCheckSecretPermission flag
const rows = await knex(TableName.SecretApprovalPolicy).select(selectAllTableCols(TableName.SecretApprovalPolicy));
if (rows.length > 0) {
for (let i = 0; i < rows.length; i += BATCH_SIZE) {
const batch = rows.slice(i, i + BATCH_SIZE);
// eslint-disable-next-line no-await-in-loop
await knex(TableName.SecretApprovalPolicy)
.whereIn(
"id",
batch.map((row) => row.id)
)
.update({ shouldCheckSecretPermission: true });
}
}
}
}
export async function down(): Promise<void> {}
+2 -1
View File
@@ -17,7 +17,8 @@ export const AuthTokensSchema = z.object({
createdAt: z.date(),
updatedAt: z.date(),
userId: z.string().uuid().nullable().optional(),
orgId: z.string().uuid().nullable().optional()
orgId: z.string().uuid().nullable().optional(),
aliasId: z.string().nullable().optional()
});
export type TAuthTokens = z.infer<typeof AuthTokensSchema>;
+3 -1
View File
@@ -36,7 +36,9 @@ export const OrganizationsSchema = z.object({
scannerProductEnabled: z.boolean().default(true).nullable().optional(),
shareSecretsProductEnabled: z.boolean().default(true).nullable().optional(),
maxSharedSecretLifetime: z.number().default(2592000).nullable().optional(),
maxSharedSecretViewLimit: z.number().nullable().optional()
maxSharedSecretViewLimit: z.number().nullable().optional(),
googleSsoAuthEnforced: z.boolean().default(false),
googleSsoAuthLastUsed: z.date().nullable().optional()
});
export type TOrganizations = z.infer<typeof OrganizationsSchema>;
@@ -17,7 +17,8 @@ export const SecretApprovalPoliciesSchema = z.object({
updatedAt: z.date(),
enforcementLevel: z.string().default("hard"),
deletedAt: z.date().nullable().optional(),
allowedSelfApprovals: z.boolean().default(true)
allowedSelfApprovals: z.boolean().default(true),
shouldCheckSecretPermission: z.boolean().nullable().optional()
});
export type TSecretApprovalPolicies = z.infer<typeof SecretApprovalPoliciesSchema>;
+2 -1
View File
@@ -16,7 +16,8 @@ export const UserAliasesSchema = z.object({
emails: z.string().array().nullable().optional(),
orgId: z.string().uuid().nullable().optional(),
createdAt: z.date(),
updatedAt: z.date()
updatedAt: z.date(),
isEmailVerified: z.boolean().default(false).nullable().optional()
});
export type TUserAliases = z.infer<typeof UserAliasesSchema>;