diff --git a/Servers/utils/validations/aiTrustCentreValidation.utils.ts b/Servers/utils/validations/aiTrustCentreValidation.utils.ts index 3feb6bc90..aa29e7a09 100644 --- a/Servers/utils/validations/aiTrustCentreValidation.utils.ts +++ b/Servers/utils/validations/aiTrustCentreValidation.utils.ts @@ -57,10 +57,10 @@ export const validateOverviewInfo = (value: any): ValidationResult => { }; } - // Validate title - if (value.title !== undefined) { + // Validate title (optional) + if (value.title !== undefined && value.title !== null && value.title !== '') { const titleValidation = validateString(value.title, 'Title', { - required: true, + required: false, minLength: AI_TRUST_CENTRE_VALIDATION_LIMITS.TITLE.MIN, maxLength: AI_TRUST_CENTRE_VALIDATION_LIMITS.TITLE.MAX, trimWhitespace: true @@ -70,10 +70,10 @@ export const validateOverviewInfo = (value: any): ValidationResult => { } } - // Validate header color - if (value.header_color !== undefined) { + // Validate header color (optional) + if (value.header_color !== undefined && value.header_color !== null && value.header_color !== '') { const colorValidation = validateString(value.header_color, 'Header color', { - required: true, + required: false, minLength: AI_TRUST_CENTRE_VALIDATION_LIMITS.HEADER_COLOR.MIN, maxLength: AI_TRUST_CENTRE_VALIDATION_LIMITS.HEADER_COLOR.MAX, trimWhitespace: true @@ -93,8 +93,8 @@ export const validateOverviewInfo = (value: any): ValidationResult => { } } - // Validate logo file ID if provided - if (value.logo !== undefined && value.logo !== null) { + // Validate logo file ID if provided (optional) + if (value.logo !== undefined && value.logo !== null && value.logo !== '') { const logoValidation = validateForeignKey(value.logo, 'Logo file ID', false); if (!logoValidation.isValid) { return logoValidation; @@ -106,6 +106,7 @@ export const validateOverviewInfo = (value: any): ValidationResult => { /** * Validates overview intro section + * Only validates text fields if they are visible and have content */ export const validateOverviewIntro = (value: any): ValidationResult => { if (!value || typeof value !== 'object') { @@ -116,8 +117,8 @@ export const validateOverviewIntro = (value: any): ValidationResult => { }; } - // Validate purpose text if provided - if (value.purpose_text !== undefined) { + // Only validate purpose text if it's visible and has content + if (value.purpose_visible && value.purpose_text !== undefined && value.purpose_text !== null && value.purpose_text !== '') { const purposeValidation = validateString(value.purpose_text, 'Purpose text', { required: false, minLength: AI_TRUST_CENTRE_VALIDATION_LIMITS.PURPOSE_TEXT.MIN, @@ -129,8 +130,8 @@ export const validateOverviewIntro = (value: any): ValidationResult => { } } - // Validate our statement text if provided - if (value.our_statement_text !== undefined) { + // Only validate statement text if it's visible and has content + if (value.our_statement_visible && value.our_statement_text !== undefined && value.our_statement_text !== null && value.our_statement_text !== '') { const statementValidation = validateString(value.our_statement_text, 'Our statement text', { required: false, minLength: AI_TRUST_CENTRE_VALIDATION_LIMITS.STATEMENT_TEXT.MIN, @@ -142,8 +143,8 @@ export const validateOverviewIntro = (value: any): ValidationResult => { } } - // Validate our mission text if provided - if (value.our_mission_text !== undefined) { + // Only validate mission text if it's visible and has content + if (value.our_mission_visible && value.our_mission_text !== undefined && value.our_mission_text !== null && value.our_mission_text !== '') { const missionValidation = validateString(value.our_mission_text, 'Our mission text', { required: false, minLength: AI_TRUST_CENTRE_VALIDATION_LIMITS.MISSION_TEXT.MIN, @@ -160,6 +161,7 @@ export const validateOverviewIntro = (value: any): ValidationResult => { /** * Validates overview company description section + * Only validates text fields if they are visible and have content */ export const validateOverviewCompanyDescription = (value: any): ValidationResult => { if (!value || typeof value !== 'object') { @@ -170,8 +172,8 @@ export const validateOverviewCompanyDescription = (value: any): ValidationResult }; } - // Validate background text if provided - if (value.background_text !== undefined) { + // Only validate background text if it's visible and has content + if (value.background_visible && value.background_text !== undefined && value.background_text !== null && value.background_text !== '') { const backgroundValidation = validateString(value.background_text, 'Background text', { required: false, minLength: AI_TRUST_CENTRE_VALIDATION_LIMITS.BACKGROUND_TEXT.MIN, @@ -183,8 +185,8 @@ export const validateOverviewCompanyDescription = (value: any): ValidationResult } } - // Validate core benefits text if provided - if (value.core_benefits_text !== undefined) { + // Only validate core benefits text if it's visible and has content + if (value.core_benefits_visible && value.core_benefits_text !== undefined && value.core_benefits_text !== null && value.core_benefits_text !== '') { const benefitsValidation = validateString(value.core_benefits_text, 'Core benefits text', { required: false, minLength: AI_TRUST_CENTRE_VALIDATION_LIMITS.CORE_BENEFITS_TEXT.MIN, @@ -196,8 +198,8 @@ export const validateOverviewCompanyDescription = (value: any): ValidationResult } } - // Validate compliance doc text if provided - if (value.compliance_doc_text !== undefined) { + // Only validate compliance doc text if it's visible and has content + if (value.compliance_doc_visible && value.compliance_doc_text !== undefined && value.compliance_doc_text !== null && value.compliance_doc_text !== '') { const complianceValidation = validateString(value.compliance_doc_text, 'Compliance document text', { required: false, minLength: AI_TRUST_CENTRE_VALIDATION_LIMITS.COMPLIANCE_DOC_TEXT.MIN, @@ -214,6 +216,7 @@ export const validateOverviewCompanyDescription = (value: any): ValidationResult /** * Validates overview terms and contact section + * Only validates text fields if they are visible and have content */ export const validateOverviewTermsAndContact = (value: any): ValidationResult => { if (!value || typeof value !== 'object') { @@ -224,8 +227,8 @@ export const validateOverviewTermsAndContact = (value: any): ValidationResult => }; } - // Validate terms text if provided - if (value.terms_text !== undefined) { + // Only validate terms text if it's visible and has content + if (value.terms_visible && value.terms_text !== undefined && value.terms_text !== null && value.terms_text !== '') { const termsValidation = validateString(value.terms_text, 'Terms text', { required: false, minLength: AI_TRUST_CENTRE_VALIDATION_LIMITS.TERMS_TEXT.MIN, @@ -237,8 +240,8 @@ export const validateOverviewTermsAndContact = (value: any): ValidationResult => } } - // Validate privacy text if provided - if (value.privacy_text !== undefined) { + // Only validate privacy text if it's visible and has content + if (value.privacy_visible && value.privacy_text !== undefined && value.privacy_text !== null && value.privacy_text !== '') { const privacyValidation = validateString(value.privacy_text, 'Privacy text', { required: false, minLength: AI_TRUST_CENTRE_VALIDATION_LIMITS.PRIVACY_TEXT.MIN, @@ -250,8 +253,8 @@ export const validateOverviewTermsAndContact = (value: any): ValidationResult => } } - // Validate email text if provided - if (value.email_text !== undefined) { + // Only validate email text if it's visible and has content + if (value.email_visible && value.email_text !== undefined && value.email_text !== null && value.email_text !== '') { const emailValidation = validateString(value.email_text, 'Email text', { required: false, minLength: AI_TRUST_CENTRE_VALIDATION_LIMITS.EMAIL_TEXT.MIN, @@ -468,11 +471,12 @@ export const validateAITrustCentreFileUpload = (file: any, type: 'logo' | 'resou /** * Business rule validation for AI Trust Centre overview + * Only validates content when the section is actually visible */ export const validateOverviewBusinessRules = (data: Partial): ValidationError[] => { const errors: ValidationError[] = []; - // Validate that if sections are visible, they have meaningful content + // Only validate intro content if intro section is visible in info if (data.info?.intro_visible && data.intro) { if (data.intro.purpose_visible && (!data.intro.purpose_text || data.intro.purpose_text.trim().length < 10)) { errors.push({ @@ -499,6 +503,7 @@ export const validateOverviewBusinessRules = (data: Partial { return validateForeignKey(value, 'User ID', false); }; +/** + * Validates project ID field + */ +export const validateProjectId = (value: any): ValidationResult => { + if (value === undefined || value === null || value === '') { + return { isValid: true }; // Optional field + } + return validateForeignKey(value, 'Project ID', false); +}; + /** * Validates due date field */ @@ -377,9 +387,9 @@ export const updateSubClauseSchema = { risksMitigated: validateRisksMitigated, // File management delete: validateFilesDelete, - // Required for file operations - user_id: (value: any) => validateForeignKey(value, 'User ID', true), - project_id: (value: any) => validateForeignKey(value, 'Project ID', true) + // Optional fields for file operations (validated conditionally when files present) + user_id: validateUserId, + project_id: validateProjectId }; /** @@ -398,16 +408,25 @@ export const updateAnnexControlSchema = { risksMitigated: validateRisksMitigated, // File management delete: validateFilesDelete, - // Required for file operations - user_id: (value: any) => validateForeignKey(value, 'User ID', true), - project_id: (value: any) => validateForeignKey(value, 'Project ID', true) + // Optional fields for file operations (validated conditionally when files present) + user_id: validateUserId, + project_id: validateProjectId }; /** * Validates subclause update data */ -export const validateUpdateSubClause = (data: any): ValidationError[] => { - const errors = validateSchema(data, updateSubClauseSchema); +export const validateUpdateSubClause = (data: any, skipFileFields: boolean = false): ValidationError[] => { + // Create a copy of the schema, excluding user_id and project_id if skipFileFields is true + const schemaToUse = skipFileFields + ? Object.fromEntries( + Object.entries(updateSubClauseSchema).filter( + ([key]) => key !== 'user_id' && key !== 'project_id' + ) + ) + : updateSubClauseSchema; + + const errors = validateSchema(data, schemaToUse); // Check if at least some meaningful data is provided const meaningfulFields = [ @@ -433,8 +452,17 @@ export const validateUpdateSubClause = (data: any): ValidationError[] => { /** * Validates annex control update data */ -export const validateUpdateAnnexControl = (data: any): ValidationError[] => { - const errors = validateSchema(data, updateAnnexControlSchema); +export const validateUpdateAnnexControl = (data: any, skipFileFields: boolean = false): ValidationError[] => { + // Create a copy of the schema, excluding user_id and project_id if skipFileFields is true + const schemaToUse = skipFileFields + ? Object.fromEntries( + Object.entries(updateAnnexControlSchema).filter( + ([key]) => key !== 'user_id' && key !== 'project_id' + ) + ) + : updateAnnexControlSchema; + + const errors = validateSchema(data, schemaToUse); // Check if at least some meaningful data is provided const meaningfulFields = [ @@ -461,10 +489,13 @@ export const validateUpdateAnnexControl = (data: any): ValidationError[] => { * Complete validation for ISO-27001 subclause updates */ export const validateCompleteSubClauseUpdate = (data: any, files?: any[]): ValidationError[] => { - const errors = validateUpdateSubClause(data); + const hasFiles = files && files.length > 0; + + // Skip user_id and project_id validation if no files are present + const errors = validateUpdateSubClause(data, !hasFiles); // Add file validation if files are present - if (files && files.length > 0) { + if (hasFiles) { const fileValidation = validateFileUploads(files); if (!fileValidation.isValid) { errors.push({ @@ -473,6 +504,25 @@ export const validateCompleteSubClauseUpdate = (data: any, files?: any[]): Valid code: fileValidation.code || 'FILE_VALIDATION_FAILED' }); } + + // Validate user_id and project_id are present when files are being uploaded + const userIdValidation = validateForeignKey(data.user_id, 'User ID', true); + if (!userIdValidation.isValid) { + errors.push({ + field: 'user_id', + message: userIdValidation.message || 'User ID is required when uploading files', + code: userIdValidation.code || 'USER_ID_REQUIRED_FOR_FILES' + }); + } + + const projectIdValidation = validateForeignKey(data.project_id, 'Project ID', true); + if (!projectIdValidation.isValid) { + errors.push({ + field: 'project_id', + message: projectIdValidation.message || 'Project ID is required when uploading files', + code: projectIdValidation.code || 'PROJECT_ID_REQUIRED_FOR_FILES' + }); + } } return errors; @@ -482,10 +532,13 @@ export const validateCompleteSubClauseUpdate = (data: any, files?: any[]): Valid * Complete validation for ISO-27001 annex control updates */ export const validateCompleteAnnexControlUpdate = (data: any, files?: any[]): ValidationError[] => { - const errors = validateUpdateAnnexControl(data); + const hasFiles = files && files.length > 0; + + // Skip user_id and project_id validation if no files are present + const errors = validateUpdateAnnexControl(data, !hasFiles); // Add file validation if files are present - if (files && files.length > 0) { + if (hasFiles) { const fileValidation = validateFileUploads(files); if (!fileValidation.isValid) { errors.push({ @@ -494,6 +547,25 @@ export const validateCompleteAnnexControlUpdate = (data: any, files?: any[]): Va code: fileValidation.code || 'FILE_VALIDATION_FAILED' }); } + + // Validate user_id and project_id are present when files are being uploaded + const userIdValidation = validateForeignKey(data.user_id, 'User ID', true); + if (!userIdValidation.isValid) { + errors.push({ + field: 'user_id', + message: userIdValidation.message || 'User ID is required when uploading files', + code: userIdValidation.code || 'USER_ID_REQUIRED_FOR_FILES' + }); + } + + const projectIdValidation = validateForeignKey(data.project_id, 'Project ID', true); + if (!projectIdValidation.isValid) { + errors.push({ + field: 'project_id', + message: projectIdValidation.message || 'Project ID is required when uploading files', + code: projectIdValidation.code || 'PROJECT_ID_REQUIRED_FOR_FILES' + }); + } } return errors; diff --git a/Servers/utils/validations/iso42001Validation.utils.ts b/Servers/utils/validations/iso42001Validation.utils.ts index d2e6fa4e8..513b27966 100644 --- a/Servers/utils/validations/iso42001Validation.utils.ts +++ b/Servers/utils/validations/iso42001Validation.utils.ts @@ -166,6 +166,16 @@ export const validateUserId = (value: any): ValidationResult => { return validateForeignKey(value, 'User ID', false); }; +/** + * Validates project ID field + */ +export const validateProjectId = (value: any): ValidationResult => { + if (value === undefined || value === null || value === '') { + return { isValid: true }; // Optional field + } + return validateForeignKey(value, 'Project ID', false); +}; + /** * Validates due date field */ @@ -420,9 +430,9 @@ export const updateSubClauseSchema = { risksMitigated: validateRisksMitigated, // File management delete: validateFilesDelete, - // Required for file operations - user_id: (value: any) => validateForeignKey(value, 'User ID', true), - project_id: (value: any) => validateForeignKey(value, 'Project ID', true) + // Optional fields for file operations (validated conditionally when files present) + user_id: validateUserId, + project_id: validateProjectId }; /** @@ -443,16 +453,25 @@ export const updateAnnexCategorySchema = { risksMitigated: validateRisksMitigated, // File management delete: validateFilesDelete, - // Required for file operations - user_id: (value: any) => validateForeignKey(value, 'User ID', true), - project_id: (value: any) => validateForeignKey(value, 'Project ID', true) + // Optional fields for file operations (validated conditionally when files present) + user_id: validateUserId, + project_id: validateProjectId }; /** * Validates subclause update data */ -export const validateUpdateSubClause = (data: any): ValidationError[] => { - const errors = validateSchema(data, updateSubClauseSchema); +export const validateUpdateSubClause = (data: any, skipFileFields: boolean = false): ValidationError[] => { + // Create a copy of the schema, excluding user_id and project_id if skipFileFields is true + const schemaToUse = skipFileFields + ? Object.fromEntries( + Object.entries(updateSubClauseSchema).filter( + ([key]) => key !== 'user_id' && key !== 'project_id' + ) + ) + : updateSubClauseSchema; + + const errors = validateSchema(data, schemaToUse); // Check if at least some meaningful data is provided const meaningfulFields = [ @@ -479,8 +498,17 @@ export const validateUpdateSubClause = (data: any): ValidationError[] => { * Validates annex category update data * Includes conditional validation for is_applicable and justification_for_exclusion */ -export const validateUpdateAnnexCategory = (data: any): ValidationError[] => { - const errors = validateSchema(data, updateAnnexCategorySchema); +export const validateUpdateAnnexCategory = (data: any, skipFileFields: boolean = false): ValidationError[] => { + // Create a copy of the schema, excluding user_id and project_id if skipFileFields is true + const schemaToUse = skipFileFields + ? Object.fromEntries( + Object.entries(updateAnnexCategorySchema).filter( + ([key]) => key !== 'user_id' && key !== 'project_id' + ) + ) + : updateAnnexCategorySchema; + + const errors = validateSchema(data, schemaToUse); // Conditional validation for justification_for_exclusion based on is_applicable const justificationValidation = validateJustificationForExclusion( @@ -577,10 +605,13 @@ export const sanitizeAnnexCategoryData = (data: any): any => { * Complete validation for ISO-42001 subclause updates */ export const validateCompleteSubClauseUpdate = (data: any, files?: any[]): ValidationError[] => { - const errors = validateUpdateSubClause(data); + const hasFiles = files && files.length > 0; + + // Skip user_id and project_id validation if no files are present + const errors = validateUpdateSubClause(data, !hasFiles); // Add file validation if files are present - if (files && files.length > 0) { + if (hasFiles) { const fileValidation = validateFileUploads(files); if (!fileValidation.isValid) { errors.push({ @@ -589,6 +620,25 @@ export const validateCompleteSubClauseUpdate = (data: any, files?: any[]): Valid code: fileValidation.code || 'FILE_VALIDATION_FAILED' }); } + + // Validate user_id and project_id are present when files are being uploaded + const userIdValidation = validateForeignKey(data.user_id, 'User ID', true); + if (!userIdValidation.isValid) { + errors.push({ + field: 'user_id', + message: userIdValidation.message || 'User ID is required when uploading files', + code: userIdValidation.code || 'USER_ID_REQUIRED_FOR_FILES' + }); + } + + const projectIdValidation = validateForeignKey(data.project_id, 'Project ID', true); + if (!projectIdValidation.isValid) { + errors.push({ + field: 'project_id', + message: projectIdValidation.message || 'Project ID is required when uploading files', + code: projectIdValidation.code || 'PROJECT_ID_REQUIRED_FOR_FILES' + }); + } } return errors; @@ -598,10 +648,13 @@ export const validateCompleteSubClauseUpdate = (data: any, files?: any[]): Valid * Complete validation for ISO-42001 annex category updates */ export const validateCompleteAnnexCategoryUpdate = (data: any, files?: any[]): ValidationError[] => { - const errors = validateUpdateAnnexCategory(data); + const hasFiles = files && files.length > 0; + + // Skip user_id and project_id validation if no files are present + const errors = validateUpdateAnnexCategory(data, !hasFiles); // Add file validation if files are present - if (files && files.length > 0) { + if (hasFiles) { const fileValidation = validateFileUploads(files); if (!fileValidation.isValid) { errors.push({ @@ -610,6 +663,25 @@ export const validateCompleteAnnexCategoryUpdate = (data: any, files?: any[]): V code: fileValidation.code || 'FILE_VALIDATION_FAILED' }); } + + // Validate user_id and project_id are present when files are being uploaded + const userIdValidation = validateForeignKey(data.user_id, 'User ID', true); + if (!userIdValidation.isValid) { + errors.push({ + field: 'user_id', + message: userIdValidation.message || 'User ID is required when uploading files', + code: userIdValidation.code || 'USER_ID_REQUIRED_FOR_FILES' + }); + } + + const projectIdValidation = validateForeignKey(data.project_id, 'Project ID', true); + if (!projectIdValidation.isValid) { + errors.push({ + field: 'project_id', + message: projectIdValidation.message || 'Project ID is required when uploading files', + code: projectIdValidation.code || 'PROJECT_ID_REQUIRED_FOR_FILES' + }); + } } return errors; diff --git a/Servers/utils/validations/modelInventoryValidation.utils.ts b/Servers/utils/validations/modelInventoryValidation.utils.ts index 8699a36fb..860058686 100644 --- a/Servers/utils/validations/modelInventoryValidation.utils.ts +++ b/Servers/utils/validations/modelInventoryValidation.utils.ts @@ -22,9 +22,9 @@ export const MODEL_INVENTORY_VALIDATION_LIMITS = { PROVIDER: { MIN: 2, MAX: 100 }, MODEL: { MIN: 2, MAX: 100 }, VERSION: { MIN: 1, MAX: 50 }, - APPROVER: { MIN: 2, MAX: 100 }, CAPABILITIES: { MIN_ITEMS: 1, MAX_ITEMS: 10 }, // SECURITY_ASSESSMENT is now a boolean field + // APPROVER is now a foreign key integer (user ID) } as const; /** @@ -99,8 +99,11 @@ export const MODEL_PROVIDER_ENUM = [ * Validates provider model field */ export const validateProviderModel = (value: any): ValidationResult => { + if (value === undefined || value === null || value === '') { + return { isValid: true }; // Optional field + } return validateString(value, 'Provider model', { - required: true, + required: false, minLength: MODEL_INVENTORY_VALIDATION_LIMITS.PROVIDER_MODEL.MIN, maxLength: MODEL_INVENTORY_VALIDATION_LIMITS.PROVIDER_MODEL.MAX, trimWhitespace: true @@ -144,15 +147,10 @@ export const validateVersion = (value: any): ValidationResult => { }; /** - * Validates approver field + * Validates approver field (user foreign key) */ export const validateApprover = (value: any): ValidationResult => { - return validateString(value, 'Approver', { - required: true, - minLength: MODEL_INVENTORY_VALIDATION_LIMITS.APPROVER.MIN, - maxLength: MODEL_INVENTORY_VALIDATION_LIMITS.APPROVER.MAX, - trimWhitespace: true - }); + return validateForeignKey(value, 'Approver', true); }; /** @@ -160,11 +158,7 @@ export const validateApprover = (value: any): ValidationResult => { */ export const validateCapabilities = (value: any): ValidationResult => { if (value === undefined || value === null) { - return { - isValid: false, - message: 'Capabilities are required', - code: 'REQUIRED_FIELD' - }; + return { isValid: true }; // Optional field } if (!Array.isArray(value)) { @@ -175,12 +169,9 @@ export const validateCapabilities = (value: any): ValidationResult => { }; } - if (value.length < MODEL_INVENTORY_VALIDATION_LIMITS.CAPABILITIES.MIN_ITEMS) { - return { - isValid: false, - message: `Capabilities array must contain at least ${MODEL_INVENTORY_VALIDATION_LIMITS.CAPABILITIES.MIN_ITEMS} item(s)`, - code: 'INSUFFICIENT_CAPABILITIES' - }; + // Allow empty array (optional field) + if (value.length === 0) { + return { isValid: true }; } if (value.length > MODEL_INVENTORY_VALIDATION_LIMITS.CAPABILITIES.MAX_ITEMS) { @@ -258,13 +249,9 @@ export const validateStatusDate = (value: any): ValidationResult => { * Validates is demo field */ export const validateIsDemo = (value: any): ValidationResult => { - // Custom boolean validation since validateBoolean is not available + // Optional field - no validation if not provided if (value === undefined || value === null) { - return { - isValid: false, - message: 'Is demo is required', - code: 'REQUIRED_FIELD' - }; + return { isValid: true }; } if (typeof value !== 'boolean') { @@ -388,36 +375,10 @@ export const validateModelInventoryCreationBusinessRules = (data: any): Validati } } - // Validate security assessment requirements for approved models - if (data.status === 'Approved') { - if (data.security_assessment !== true) { - errors.push({ - field: 'security_assessment', - message: 'Approved models must have security assessment completed (true)', - code: 'SECURITY_ASSESSMENT_REQUIRED' - }); - } - } - - // Validate security assessment for restricted models - if (data.status === 'Restricted') { - if (data.security_assessment !== true) { - errors.push({ - field: 'security_assessment', - message: 'Restricted models must have security assessment completed (true)', - code: 'SECURITY_ASSESSMENT_REQUIRED' - }); - } - } - - // Validate security assessment for blocked models - if (data.status === 'Blocked') { - // Blocked models may have security_assessment as false, indicating failed assessment - // This is acceptable for blocked status - } + // Security assessment is no longer required for any status // Validate capabilities selection - if (data.capabilities && Array.isArray(data.capabilities)) { + if (data.capabilities && Array.isArray(data.capabilities) && data.capabilities.length > 0) { // Check for logical capability combinations const hasVision = data.capabilities.includes('Vision'); const hasMultimodal = data.capabilities.includes('Multimodal'); @@ -500,31 +461,9 @@ export const validateModelInventoryCreationBusinessRules = (data: any): Validati }); } - // Validate security assessment consistency with status - if (data.security_assessment === false && (data.status === 'Approved' || data.status === 'Restricted')) { - errors.push({ - field: 'security_assessment', - message: 'Models with failed security assessment cannot be Approved or Restricted', - code: 'FAILED_SECURITY_ASSESSMENT_CONFLICT' - }); - } - - // Validate that pending models don't claim completed security assessment prematurely - if (data.status === 'Pending' && data.security_assessment === true) { - // This is actually fine - pending models can have completed security assessment - // They just haven't been reviewed for final approval yet - } + // Security assessment is no longer enforced for any status transitions - // Validate approver field format - if (data.approver) { - if (!data.approver.includes(' ') || data.approver.length < 5) { - errors.push({ - field: 'approver', - message: 'Approver should include full name (first and last name)', - code: 'INVALID_APPROVER_FORMAT' - }); - } - } + // Approver is now a user ID (foreign key), so no format validation needed return errors; }; @@ -549,14 +488,7 @@ export const validateModelInventoryUpdateBusinessRules = (data: any, existingDat } if (existingData.status === 'Pending' && data.status === 'Approved') { - // Ensure security assessment is completed for approval - if (data.security_assessment !== true) { - errors.push({ - field: 'security_assessment', - message: 'Security assessment must be completed (true) for approval', - code: 'SECURITY_ASSESSMENT_REQUIRED_FOR_APPROVAL' - }); - } + // Allow approval without security assessment requirement } if (existingData.status === 'Pending' && data.status === 'Restricted') { @@ -584,17 +516,6 @@ export const validateModelInventoryUpdateBusinessRules = (data: any, existingDat } } - // Validate version updates - if (data.version && existingData?.version) { - if (data.version === existingData.version && data.status !== existingData.status) { - errors.push({ - field: 'version', - message: 'Version should be updated when changing model status significantly', - code: 'VERSION_UPDATE_REQUIRED' - }); - } - } - // Validate version format if (data.version) { const versionPattern = /^v?\d+(\.\d+)*(-[a-zA-Z0-9-]+)?(\+[a-zA-Z0-9-]+)?$/; @@ -607,16 +528,7 @@ export const validateModelInventoryUpdateBusinessRules = (data: any, existingDat } } - // Validate security assessment for approved promotion - if (data.status === 'Approved') { - if (data.security_assessment !== true) { - errors.push({ - field: 'security_assessment', - message: 'Approved models must have security assessment completed (true)', - code: 'SECURITY_ASSESSMENT_REQUIRED' - }); - } - } + // Security assessment is no longer required for approved status // Validate demo flag changes if (data.is_demo !== undefined && existingData?.is_demo !== undefined) {