fix(security): resolve audit findings and compilation errors (Phase 6)
Security fixes: - Add startup warning for default JWT secret in config - Add enum validation for priority, recipient_type, channel fields - Add pagination size cap (max 100) via safe_page_size() - Return generic "权限不足" instead of specific permission names Compilation fixes: - Fix missing standard fields in ActiveModel for tokens/process_variables - Fix migration imports for Statement/DatabaseBackend/Uuid - Add version_field to process_definition ActiveModel Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -26,6 +26,9 @@ mod m20260413_000023_create_message_templates;
|
||||
mod m20260413_000024_create_messages;
|
||||
mod m20260413_000025_create_message_subscriptions;
|
||||
mod m20260413_000026_create_audit_logs;
|
||||
mod m20260414_000027_fix_unique_indexes_soft_delete;
|
||||
mod m20260414_000028_add_standard_fields_to_tokens;
|
||||
mod m20260414_000029_add_standard_fields_to_process_variables;
|
||||
|
||||
pub struct Migrator;
|
||||
|
||||
@@ -59,6 +62,9 @@ impl MigratorTrait for Migrator {
|
||||
Box::new(m20260413_000024_create_messages::Migration),
|
||||
Box::new(m20260413_000025_create_message_subscriptions::Migration),
|
||||
Box::new(m20260413_000026_create_audit_logs::Migration),
|
||||
Box::new(m20260414_000027_fix_unique_indexes_soft_delete::Migration),
|
||||
Box::new(m20260414_000028_add_standard_fields_to_tokens::Migration),
|
||||
Box::new(m20260414_000029_add_standard_fields_to_process_variables::Migration),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
use sea_orm_migration::prelude::*;
|
||||
use sea_orm::Statement;
|
||||
use sea_orm::DatabaseBackend;
|
||||
|
||||
/// Recreate unique indexes on roles and permissions to include soft-delete awareness.
|
||||
#[derive(DeriveMigrationName)]
|
||||
pub struct Migration;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl MigrationTrait for Migration {
|
||||
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.get_connection()
|
||||
.execute(Statement::from_string(
|
||||
DatabaseBackend::Postgres,
|
||||
"DROP INDEX IF EXISTS idx_roles_tenant_code".to_string(),
|
||||
))
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.get_connection()
|
||||
.execute(Statement::from_string(
|
||||
DatabaseBackend::Postgres,
|
||||
"DROP INDEX IF EXISTS idx_permissions_tenant_code".to_string(),
|
||||
))
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.get_connection()
|
||||
.execute(Statement::from_string(
|
||||
DatabaseBackend::Postgres,
|
||||
"CREATE UNIQUE INDEX idx_roles_tenant_code \
|
||||
ON roles (tenant_id, code) \
|
||||
WHERE deleted_at IS NULL"
|
||||
.to_string(),
|
||||
))
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.get_connection()
|
||||
.execute(Statement::from_string(
|
||||
DatabaseBackend::Postgres,
|
||||
"CREATE UNIQUE INDEX idx_permissions_tenant_code \
|
||||
ON permissions (tenant_id, code) \
|
||||
WHERE deleted_at IS NULL"
|
||||
.to_string(),
|
||||
))
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.get_connection()
|
||||
.execute(Statement::from_string(
|
||||
DatabaseBackend::Postgres,
|
||||
"DROP INDEX IF EXISTS idx_roles_tenant_code".to_string(),
|
||||
))
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.get_connection()
|
||||
.execute(Statement::from_string(
|
||||
DatabaseBackend::Postgres,
|
||||
"DROP INDEX IF EXISTS idx_permissions_tenant_code".to_string(),
|
||||
))
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.get_connection()
|
||||
.execute(Statement::from_string(
|
||||
DatabaseBackend::Postgres,
|
||||
"CREATE UNIQUE INDEX idx_roles_tenant_code \
|
||||
ON roles (tenant_id, code)"
|
||||
.to_string(),
|
||||
))
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.get_connection()
|
||||
.execute(Statement::from_string(
|
||||
DatabaseBackend::Postgres,
|
||||
"CREATE UNIQUE INDEX idx_permissions_tenant_code \
|
||||
ON permissions (tenant_id, code)"
|
||||
.to_string(),
|
||||
))
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
use sea_orm_migration::prelude::*;
|
||||
|
||||
/// 为 tokens 表添加缺失的标准字段: updated_at, created_by, updated_by, deleted_at, version。
|
||||
///
|
||||
/// tokens 表原始迁移缺少 ERP 标准要求的审计和乐观锁字段。
|
||||
#[derive(DeriveMigrationName)]
|
||||
pub struct Migration;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl MigrationTrait for Migration {
|
||||
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.alter_table(
|
||||
Table::alter()
|
||||
.table(Tokens::Table)
|
||||
.add_column(
|
||||
ColumnDef::new(Tokens::UpdatedAt)
|
||||
.timestamp_with_time_zone()
|
||||
.not_null()
|
||||
.default(Expr::current_timestamp()),
|
||||
)
|
||||
.add_column(
|
||||
ColumnDef::new(Tokens::CreatedBy)
|
||||
.uuid()
|
||||
.not_null()
|
||||
.default(Expr::val("00000000-0000-0000-0000-000000000000")),
|
||||
)
|
||||
.add_column(
|
||||
ColumnDef::new(Tokens::UpdatedBy)
|
||||
.uuid()
|
||||
.not_null()
|
||||
.default(Expr::val("00000000-0000-0000-0000-000000000000")),
|
||||
)
|
||||
.add_column(
|
||||
ColumnDef::new(Tokens::DeletedAt)
|
||||
.timestamp_with_time_zone()
|
||||
.null(),
|
||||
)
|
||||
.add_column(
|
||||
ColumnDef::new(Tokens::Version)
|
||||
.integer()
|
||||
.not_null()
|
||||
.default(1),
|
||||
)
|
||||
.to_owned(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.alter_table(
|
||||
Table::alter()
|
||||
.table(Tokens::Table)
|
||||
.drop_column(Tokens::UpdatedAt)
|
||||
.drop_column(Tokens::CreatedBy)
|
||||
.drop_column(Tokens::UpdatedBy)
|
||||
.drop_column(Tokens::DeletedAt)
|
||||
.drop_column(Tokens::Version)
|
||||
.to_owned(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(DeriveIden)]
|
||||
enum Tokens {
|
||||
Table,
|
||||
UpdatedAt,
|
||||
CreatedBy,
|
||||
UpdatedBy,
|
||||
DeletedAt,
|
||||
Version,
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
use sea_orm_migration::prelude::*;
|
||||
|
||||
/// 为 process_variables 表添加缺失的标准字段: created_at, updated_at, created_by, updated_by, deleted_at, version。
|
||||
///
|
||||
/// process_variables 表原始迁移缺少 ERP 标准要求的审计和乐观锁字段。
|
||||
#[derive(DeriveMigrationName)]
|
||||
pub struct Migration;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl MigrationTrait for Migration {
|
||||
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.alter_table(
|
||||
Table::alter()
|
||||
.table(ProcessVariables::Table)
|
||||
.add_column(
|
||||
ColumnDef::new(ProcessVariables::CreatedAt)
|
||||
.timestamp_with_time_zone()
|
||||
.not_null()
|
||||
.default(Expr::current_timestamp()),
|
||||
)
|
||||
.add_column(
|
||||
ColumnDef::new(ProcessVariables::UpdatedAt)
|
||||
.timestamp_with_time_zone()
|
||||
.not_null()
|
||||
.default(Expr::current_timestamp()),
|
||||
)
|
||||
.add_column(
|
||||
ColumnDef::new(ProcessVariables::CreatedBy)
|
||||
.uuid()
|
||||
.not_null()
|
||||
.default(Expr::val("00000000-0000-0000-0000-000000000000")),
|
||||
)
|
||||
.add_column(
|
||||
ColumnDef::new(ProcessVariables::UpdatedBy)
|
||||
.uuid()
|
||||
.not_null()
|
||||
.default(Expr::val("00000000-0000-0000-0000-000000000000")),
|
||||
)
|
||||
.add_column(
|
||||
ColumnDef::new(ProcessVariables::DeletedAt)
|
||||
.timestamp_with_time_zone()
|
||||
.null(),
|
||||
)
|
||||
.add_column(
|
||||
ColumnDef::new(ProcessVariables::Version)
|
||||
.integer()
|
||||
.not_null()
|
||||
.default(1),
|
||||
)
|
||||
.to_owned(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.alter_table(
|
||||
Table::alter()
|
||||
.table(ProcessVariables::Table)
|
||||
.drop_column(ProcessVariables::CreatedAt)
|
||||
.drop_column(ProcessVariables::UpdatedAt)
|
||||
.drop_column(ProcessVariables::CreatedBy)
|
||||
.drop_column(ProcessVariables::UpdatedBy)
|
||||
.drop_column(ProcessVariables::DeletedAt)
|
||||
.drop_column(ProcessVariables::Version)
|
||||
.to_owned(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(DeriveIden)]
|
||||
enum ProcessVariables {
|
||||
Table,
|
||||
CreatedAt,
|
||||
UpdatedAt,
|
||||
CreatedBy,
|
||||
UpdatedBy,
|
||||
DeletedAt,
|
||||
Version,
|
||||
}
|
||||
Reference in New Issue
Block a user