-
Notifications
You must be signed in to change notification settings - Fork 188
fix(deps): update dependency valibot to v1.2.0 [security] #4018
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Finished running flow.
|
||||||||||||
|
Important Review skippedBot user detected. To trigger a single review, invoke the You can disable this status message by setting the Comment |
Check changeset necessityStatus: REQUIRED Reason:
Changeset (copy & paste):---
"@liam-hq/cli": patch
"@liam-hq/erd-core": patch
"@liam-hq/schema": patch
---
- 🐛 Update valibot to v1.2.0 with security fix and improvements
- Bump valibot from 1.1.0 to 1.2.0 to address ReDoS in `emoji` validator and include upstream enhancements |
🤖 Agent Deep Modeling ExecutionProcessing time: 5m 29s View DetailsCommand Output
RUN v3.2.4 /home/runner/work/liam/liam/frontend/internal-packages/agent (node:7732) ExperimentalWarning: WASI is an experimental feature and might change at any time ✅ [INFO] 2025-11-30T16:10:18.021Z 🧠 Thinking (pm)... Producing BRD Checklist I need to act as the PM Agent and create a checklist while analyzing requirements for the BRD, structured into test cases. The process involves potentially using a web search, but that's not necessary here since it's a standard user management system. I’ll structure the requirements into test cases, save them using the specified tool, and ensure to clearly outline the goal and test cases. The output also needs a concise checklist as per the developer instructions. Structuring BRD Requirements I’m thinking about including additional BRD content in my assistant text before using the processAnalyzedRequirementsTool to save everything. The system suggests I work autonomously, so I'll assume the requirements for a simple user management system that covers Users, Roles, Permissions, and more. I need to create categories like User Accounts, Authentication & Security, and Audit & Logging while preparing test cases for INSERT, UPDATE, DELETE, and SELECT operations. I’ll also ensure the QA team can verify the database design fits the requirements even without an existing schema. Preparing BRD Requirements I need to prepare requirements for the BRD without needing to create the actual database schema. However, the BRD needs to guide the DB Agent by including entities, attributes, relationships, and constraints, so an ER outline might be beneficial. The tool only allows for a goal and test cases when saving, but I can add more in the assistant text. I’ll specify entities such as User, Role, Permission, along with junction tables. I also want to include non-functional requirements like data retention and PII handling while keeping everything concise and managing acceptance criteria for the test cases. Defining Test Cases for User Management I'm thinking about how to insert a new user with email validation and reject duplicate emails. I should consider updates to the password and possibly enforce a history requirement later. I’ll also need to handle edge cases like login attempts with incorrect passwords, ensuring that suspended users can't log in and assigning multiple roles while preventing duplicates. My test cases will need to map to SQL operations, focusing on actions like INSERT and checking constraints. For example, I’ll create cases for inserting users with required fields and formatting constraints, knowing not all databases enforce email formats easily. Crafting the BRD and Test Cases I'm focusing on creating requirements for a database-level BRD with enforced constraints like NOT NULL and UNIQUE. I want to categorize the test cases under User Accounts, Roles, and Permissions, including negative cases for foreign key violations and duplicates. The checklist will include the overview, scope, user roles, data model summary, enumerations, behaviors, validation constraints, security, and audit triggers. I need to ensure success confirmation after saving the analyzed requirements, while keeping the count of categories manageable, around 7-10. Test cases will be structured to validate various operations for each category clearly. Developing Test Cases and BRD Structure I'm preparing test cases for a user management system, focusing on requirements like creating and managing user accounts, roles, and permissions. For each category, I’ll define SQL operations to ensure data integrity, with special attention to constraints like unique emails and foreign key relationships. I'll also craft the BRD content to include an overview, scope, and detailed data model, ensuring clarity in the presented test cases. The final output will confirm success after the tool call while adhering to operational constraints. Keeping the categories manageable around eight should work well! Compiling the BRD I'm working on the Business Requirements Document (BRD) now. It will outline the objective, list functional requirements like managing users, roles, permissions, and logging, while noting what’s out of scope like SSO or complex password policies at the database level. I’ll identify key actors like System Admins and Regular Users. For the data model, I’ll define entities with fields and constraints, ensuring to mention the rules, such as allowing users to have no roles. I'll also include audit and compliance, while keeping everything concise before calling the tool with clear category keys for the test cases. ⏺ (pm): Checklist
Business Requirements Document (BRD): Simple User Management System
Test Scenarios for QA (business-focused, mapped to SQL operations)
Saving analyzed requirements and testcases now. 🧠 Thinking (pm)... Evaluating SQL operation types The instruction specifies that each test case needs a SQL operation type that aligns with the operation being tested. For instance, recording an audit log should be an INSERT action, not a SELECT. However, I noticed that the example "SELECT: Record an audit log for user creation" incorrectly uses SELECT instead of INSERT. It seems like we should correct that to "INSERT: Record an audit log for user creation" and do the same for any similar cases, like user status change. Clarifying test cases The third case "INSERT: Prevent audit log entries with invalid action types" is indeed an INSERT negative case, which is correct. Looking at the reporting and access queries, we have multiple SELECT statements like listing users and counting users by status. For data integrity, there are INSERT statements enforcing email uniqueness and referential integrity on foreign keys. I think we should consider including negative SELECT tests, such as checking if expired password reset tokens return none. It’s important to ensure our QA test cases cover both positive and negative scenarios. Adding a "Security and privacy" section could be beneficial, but maybe we don't need additional test cases for that right now. Ensuring proper saving format We need to make sure that saving uses the exact format, where category keys map to arrays of objects that include title and type values. Before significant tool calls, I should state a one-liner summarizing the purpose and minimal inputs. For the processAnalyzedRequirementsTool, during the "Save Requirements" step, I could frame this as: "Save analyzed BRD goal and QA test cases for downstream tools." After making a tool call, I should confirm successful completion and also ensure the earlier BRD is mentioned in that message. Delivering the BRD again The user has seen the content before, but the current instruction seems to require delivering the BRD again. Even though the previous assistant provided a BRD, it’s important to fulfill the current request. I think it would be effective to present a concise checklist alongside the BRD. The guidelines allow for minimal formatting, so using bullet points and numbered sections is fine. Plus, we need to ensure that the DB Agent can design the database with the included entities and constraints, while the QA Agent can verify with the test cases provided. Crafting the test cases and BRD I think we should enhance our definitions with enumerations, indexes, and a partial unique index for the email field, specifically when deleted_at is null. We should be clear that the RDBMS assumed is PostgreSQL. Including "phone" fields isn't necessary. We need to mention "status enum values," "audit action enum values," and ensure there is an "active_users view," which is included. For the tool call, I’ll prepare a payload that defines a production-ready BRD for a secure user management system. This includes categories and test cases for User Accounts, Roles, Permissions, and more. After the function call, we will confirm successful saving of the requirements while keeping the formatting simple and concise. ⏺ (pm): Purpose: Save the finalized BRD goal and QA-ready testcases for the simple user management system; Inputs: goal string and categorized testcases with titles and SQL types. 🔧 processAnalyzedRequirementsTool() ⎿ processAnalyzedRequirementsTool: Requirements processed and streamed successfully 🧠 Thinking (db)... Planning database tables I’m thinking about how to use the tool to create tables effectively. I need to establish the purpose and inputs before making the call. I want to include tables for users, roles, permissions, and more, while considering active user views. The tool supports creating indexes and constraints, but I need to implement soft-delete and ensure unique emails where deleted timestamps are null. I think I can use techniques like unique indexes, but there are limitations I’m navigating through. Clarifying index constraints I'm figuring out how the tool handles index types and predicates. While it accepts an index type string, it can't handle predicates. I want a unique index on email and deleted_at to ensure only one active email, but I realize that having both as null can create duplicates. Since SQL treats nulls uniquely, that's incorrect. I should use a boolean flag for is_deleted, allowing just one active entry, while the duplicates are prevented effectively. Adding the is_deleted flag seems like a solid solution! Defining database structure I’m thinking about creating a status enum for user statuses like active, suspended, and deactivated. The tool supports enums, which is great! I want to set up check constraints to make sure the statuses fit within the enum. Moving forward, I'll define primary keys using Planning active_users table I need to use the tools effectively for making schema changes. Since creating a true view isn't supported, I can create a table named ⏺ (db): Purpose: Create enums and tables for user management including users, roles, permissions, mappings, tokens, and audit logs. Minimal inputs: table names, columns (types, defaults, notNull), indexes, and constraints. Now applying the migration to add enums and the required tables with constraints and indexes. 🔧 createMigrationTool() ⎿ createMigrationTool: Schema successfully updated. The operations have been applied to the database schema, DDL validation successful (94/94 statements executed successfully), and new version created. ⏺ (db): Operation purpose: Added enums and all required tables (users, roles, permissions, user_roles, role_permissions, password_reset_tokens, audit_logs, active_users view placeholder). Minimal inputs: names, columns, indexes, constraints, and enum values. Validation: Migration applied successfully; DDL validated (94/94 statements executed). Summary of changes made (confirmed):
Status: Schema creation completed and validated. If you want, I can:
🔧 saveTestcase() 🔧 saveTestcase() 🔧 saveTestcase() 🔧 saveTestcase() 🔧 saveTestcase() 🔧 saveTestcase() 🔧 saveTestcase() 🔧 saveTestcase() 🔧 saveTestcase() 🔧 saveTestcase() 🔧 saveTestcase() 🔧 saveTestcase() 🔧 saveTestcase() 🔧 saveTestcase() 🔧 saveTestcase() 🔧 saveTestcase() 🔧 saveTestcase() 🔧 saveTestcase() 🔧 saveTestcase() 🔧 saveTestcase() 🔧 saveTestcase() 🔧 saveTestcase() 🔧 saveTestcase() 🔧 saveTestcase() ⎿ saveTestcase: Successfully saved SQL for test case "Reject duplicate permission code" in category "Permissions" 🔧 saveTestcase() 🔧 saveTestcase() 🔧 saveTestcase() 🔧 saveTestcase() 🔧 saveTestcase() 🔧 saveTestcase() 🔧 saveTestcase() ⎿ saveTestcase: Successfully saved SQL for test case "Reject duplicate role name" in category "Roles" ⎿ saveTestcase: Successfully saved SQL for test case "Update a role's description" in category "Roles" ⎿ saveTestcase: Successfully saved SQL for test case "Create a new permission with unique code" in category "Permissions" ⎿ saveTestcase: Successfully saved SQL for test case "Reject user creation without email" in category "User Accounts" ⎿ saveTestcase: Successfully saved SQL for test case "Prevent deleting a role that is assigned to users" in category "Roles" ⎿ saveTestcase: Successfully saved SQL for test case "Reject user creation with a duplicate email" in category "User Accounts" ⎿ saveTestcase: Successfully saved SQL for test case "Reject assignment to a non-existent user" in category "User-Role Assignments" ⎿ saveTestcase: Successfully saved SQL for test case "Allow re-using email of a soft-deleted user" in category "User Accounts" ⎿ saveTestcase: Successfully saved SQL for test case "Consume a password reset token" in category "Password Reset Tokens" ⎿ saveTestcase: Successfully saved SQL for test case "Prevent duplicate role-permission mapping" in category "Role-Permission Mappings" ⎿ saveTestcase: Successfully saved SQL for test case "Prevent invalid user status values" in category "User Accounts" ⎿ saveTestcase: Successfully saved SQL for test case "Prevent audit log entries with invalid action types" in category "Audit Logging" ⎿ saveTestcase: Successfully saved SQL for test case "Update a permission's description" in category "Permissions" ⎿ saveTestcase: Successfully saved SQL for test case "List only currently active (non-deleted) users" in category "Account Lifecycle" ⎿ saveTestcase: Successfully saved SQL for test case "Prevent deleting a permission that is assigned to roles" in category "Permissions" ⎿ saveTestcase: Successfully saved SQL for test case "Assign a role to a user" in category "User-Role Assignments" ⎿ saveTestcase: Successfully saved SQL for test case "Create a password reset token for a user" in category "Password Reset Tokens" 🔧 saveTestcase() ⎿ saveTestcase: Successfully saved SQL for test case "Create a new role with unique name" in category "Roles" 🔧 saveTestcase() ⎿ saveTestcase: Successfully saved SQL for test case "Find users without any role assigned" in category "Reporting & Access Queries" 🔧 saveTestcase() 🔧 saveTestcase() ⎿ saveTestcase: Successfully saved SQL for test case "Record an audit log for user status change" in category "Audit Logging" 🔧 saveTestcase() ⎿ saveTestcase: Successfully saved SQL for test case "Prevent duplicate user-role assignment" in category "User-Role Assignments" ⎿ saveTestcase: Successfully saved SQL for test case "Enforce referential integrity on role_permission foreign keys" in category "Data Integrity and Constraints" ⎿ saveTestcase: Successfully saved SQL for test case "Record an audit log for user creation" in category "Audit Logging" ⎿ saveTestcase: Successfully saved SQL for test case "Attach a permission to a role" in category "Role-Permission Mappings" ⎿ saveTestcase: Successfully saved SQL for test case "List users with their assigned roles" in category "Reporting & Access Queries" ⎿ saveTestcase: Successfully saved SQL for test case "Suspend a user account" in category "Account Lifecycle" ⎿ saveTestcase: Successfully saved SQL for test case "Create a new active user with required fields" in category "User Accounts" ⎿ saveTestcase: Successfully saved SQL for test case "View active users only via active_users view" in category "User Accounts" ⎿ saveTestcase: Successfully saved SQL for test case "Count users by status for admin dashboard" in category "Reporting & Access Queries" ⎿ saveTestcase: Successfully saved SQL for test case "Delete expired password reset tokens during cleanup" in category "Password Reset Tokens" ⎿ saveTestcase: Successfully saved SQL for test case "Reactivate a suspended user account" in category "Account Lifecycle" ⎿ saveTestcase: Successfully saved SQL for test case "Enforce referential integrity on user_role foreign keys" in category "Data Integrity and Constraints" ⎿ saveTestcase: Successfully saved SQL for test case "Prevent using an expired or already consumed token" in category "Password Reset Tokens" 🔧 saveTestcase() ⎿ saveTestcase: Successfully saved SQL for test case "Enforce email uniqueness excluding soft-deleted users" in category "Data Integrity and Constraints" 🔧 saveTestcase() ⎿ saveTestcase: Successfully saved SQL for test case "Deactivate a user account" in category "Account Lifecycle" 🔧 saveTestcase() 🔧 saveTestcase() 🔧 saveTestcase() 🔧 saveTestcase() ⎿ saveTestcase: Successfully saved SQL for test case "Update a user's profile details" in category "User Accounts" ⎿ saveTestcase: Successfully saved SQL for test case "List all effective permissions for a specific user" in category "Reporting & Access Queries" ⎿ saveTestcase: Successfully saved SQL for test case "Reject mapping to a non-existent permission" in category "Role-Permission Mappings" ⎿ saveTestcase: Successfully saved SQL for test case "Remove a permission from a role" in category "Role-Permission Mappings" ⎿ saveTestcase: Successfully saved SQL for test case "Remove a role from a user" in category "User-Role Assignments" ⎿ saveTestcase: Successfully saved SQL for test case "Soft-delete a user and retain history" in category "User Accounts" ⎿ runTestTool: 30/42 test cases passed, 12 failed ❌ Test Case: Reject user creation with a duplicate emailError: `1 test(s) failed:Test 4: threw 23502 SELECT lives_ok($$INSERT INTO users (email, password_hash) VALUES ('[email protected]', 'hash1')$$, 'Setup: insert first user with email');
SELECT throws_ok($$INSERT INTO users (email, password_hash) VALUES ('[email protected]', 'hash2')$$, '23505');
SELECT lives_ok($$INSERT INTO users (email, password_hash, is_deleted) VALUES ('[email protected]', 'hash2', true)$$, 'Should allow same email when previous is soft-deleted (is_deleted = true)');
SELECT throws_ok($$INSERT INTO users (email, password_hash, is_deleted) VALUES (NULL, 'hash')$$, '23502');
SELECT is((SELECT COUNT(*) FROM users WHERE email = '[email protected]'), 2::bigint, 'There should be two records with the same email when one is soft-deleted');❌ Test Case: Soft-delete a user and retain historyError: `1 test(s) failed:Test 6: Perform hard delete should fail due to FK restrict from user_roles and other relations -- Test: Soft-delete a user and retain history (DELETE test)
-- Setup: create role and user, assign role, create audit log and password token referencing user
SELECT lives_ok($$INSERT INTO roles (id, name) VALUES (gen_random_uuid(), 'tester')$$, 'Setup: insert role');
SELECT lives_ok($$INSERT INTO users (id, email, status, password_hash, is_deleted) VALUES (gen_random_uuid(), '[email protected]', 'active', 'hash', false)$$, 'Setup: insert user');
-- Capture user id for references
SELECT lives_ok($$INSERT INTO user_roles (id, user_id, role_id) VALUES (gen_random_uuid(), (SELECT id FROM users WHERE email = '[email protected]'), (SELECT id FROM roles WHERE name = 'tester'))$$, 'Setup: assign role to user');
SELECT lives_ok($$INSERT INTO password_reset_tokens (id, token, user_id, expires_at) VALUES (gen_random_uuid(), 'tok1', (SELECT id FROM users WHERE email = '[email protected]'), now() + interval '1 hour')$$, 'Setup: insert password reset token');
SELECT lives_ok($$INSERT INTO audit_logs (action, details, actor_id, target_user_id) VALUES ('user_created', '{}'::jsonb, NULL, (SELECT id FROM users WHERE email = '[email protected]'))$$, 'Setup: insert audit log for user');
-- Perform soft-delete: set is_deleted=true and deleted_at
SELECT lives_ok($$DELETE FROM users WHERE id = (SELECT id FROM users WHERE email = '[email protected]')$$, 'Perform hard delete should fail due to FK restrict from user_roles and other relations');
-- The schema uses soft-delete; ensure cascading protections: attempting to hard delete should raise foreign key RESTRICT (23503)
SELECT throws_ok($$DELETE FROM users WHERE email = '[email protected]'$$, '23503');
-- Instead perform the soft-delete update
SELECT lives_ok($$UPDATE users SET is_deleted = true, deleted_at = now() WHERE email = '[email protected]'$$, 'Soft-delete: mark user as deleted');
-- Verify user remains in users table but flagged
SELECT is((SELECT is_deleted FROM users WHERE email = '[email protected]'), true, 'User is_deleted flag should be true after soft-delete');
SELECT ok((SELECT deleted_at IS NOT NULL FROM users WHERE email = '[email protected]'), 'deleted_at should be set after soft-delete');
-- Verify related records still exist and retain history: user_roles and password_reset_tokens and audit_logs should still reference the user id
SELECT is((SELECT COUNT(*) FROM user_roles WHERE user_id = (SELECT id FROM users WHERE email = '[email protected]')), 1::bigint, 'User_roles should still reference the soft-deleted user');
SELECT is((SELECT COUNT(*) FROM password_reset_tokens WHERE user_id = (SELECT id FROM users WHERE email = '[email protected]')), 1::bigint, 'Password reset token should still reference the soft-deleted user');
SELECT is((SELECT COUNT(*) FROM audit_logs WHERE target_user_id = (SELECT id FROM users WHERE email = '[email protected]')), 1::bigint, 'Audit log should still reference the soft-deleted user');
-- Verify unique index allows re-creating a user with same email when previous is_deleted = true
SELECT lives_ok($$INSERT INTO users (id, email, status, password_hash, is_deleted) VALUES (gen_random_uuid(), '[email protected]', 'active', 'hash2', false)$$, 'Should allow inserting new active user with same email after previous soft-delete');
SELECT is((SELECT COUNT(*) FROM users WHERE email = '[email protected]' AND is_deleted = false), 1::bigint, 'There should be one active user with the email');
-- Cleanup: remove test users and role
SELECT lives_ok($$DELETE FROM user_roles WHERE user_id IN (SELECT id FROM users WHERE email = '[email protected]')$$, 'Cleanup: delete user_roles');
SELECT lives_ok($$DELETE FROM password_reset_tokens WHERE user_id IN (SELECT id FROM users WHERE email = '[email protected]')$$, 'Cleanup: delete tokens');
SELECT lives_ok($$DELETE FROM users WHERE email = '[email protected]'$$, 'Cleanup: delete users');
SELECT lives_ok($$DELETE FROM roles WHERE name = 'tester'$$, 'Cleanup: delete role');❌ Test Case: View active users only via active_users viewError: `4 test(s) failed:Test 4: active_users view should return only non-deleted users (active and suspended count) SELECT lives_ok($$INSERT INTO users (email, password_hash, status, is_deleted, full_name) VALUES ('[email protected]','hash','active', false, 'Active One')$$, 'Setup: insert active user');
SELECT lives_ok($$INSERT INTO users (email, password_hash, status, is_deleted, full_name) VALUES ('[email protected]','hash','active', true, 'Deleted User')$$, 'Setup: insert soft-deleted user');
SELECT lives_ok($$INSERT INTO users (email, password_hash, status, is_deleted, full_name) VALUES ('[email protected]','hash','suspended', false, 'Suspended User')$$, 'Setup: insert suspended user');
SELECT is((SELECT COUNT(*) FROM active_users), 2::bigint, 'active_users view should return only non-deleted users (active and suspended count)');
SELECT results_eq($$SELECT id, email::text, status::text, full_name::text, created_at FROM active_users ORDER BY email$$, $$SELECT id, email::text, status::text, full_name::text, created_at FROM users WHERE is_deleted = false ORDER BY email$$, 'active_users view should mirror non-deleted users from users table');
SELECT ok((SELECT COUNT(*) FROM active_users WHERE email = '[email protected]') = 0, 'deleted user should not appear in active_users view');
SELECT ok((SELECT COUNT(*) FROM active_users WHERE email = '[email protected]') = 1, 'active user should appear in active_users view');
SELECT ok((SELECT COUNT(*) FROM active_users WHERE status::text = 'suspended') = 1, 'suspended (non-deleted) users should appear in active_users view');❌ Test Case: Attach a permission to a roleError: `2 test(s) failed:Test 4: threw 23503 SELECT lives_ok($$INSERT INTO roles (id, name) VALUES (gen_random_uuid(), 'test_role_attach_perm')$$, 'Setup: create role');
SELECT lives_ok($$INSERT INTO permissions (id, code) VALUES (gen_random_uuid(), 'test.permission.attach')$$, 'Setup: create permission');
SELECT lives_ok($$INSERT INTO role_permissions (role_id, permission_id) VALUES ((SELECT id FROM roles WHERE name = 'test_role_attach_perm'), (SELECT id FROM permissions WHERE code = 'test.permission.attach'))$$, 'Should successfully attach permission to role');
SELECT throws_ok($$INSERT INTO role_permissions (role_id, permission_id) VALUES ((SELECT id FROM roles WHERE name = 'nonexistent'), (SELECT id FROM permissions WHERE code = 'test.permission.attach'))$$, '23503');
SELECT throws_ok($$INSERT INTO role_permissions (role_id, permission_id) VALUES ((SELECT id FROM roles WHERE name = 'test_role_attach_perm'), (SELECT id FROM permissions WHERE code = 'nonexistent'))$$, '23503');
SELECT is((SELECT COUNT(*) FROM role_permissions WHERE role_id = (SELECT id FROM roles WHERE name = 'test_role_attach_perm') AND permission_id = (SELECT id FROM permissions WHERE code = 'test.permission.attach')), 1::bigint, 'Role should have exactly one mapping to the permission');
SELECT throws_ok($$INSERT INTO role_permissions (role_id, permission_id) VALUES ((SELECT id FROM roles WHERE name = 'test_role_attach_perm'), (SELECT id FROM permissions WHERE code = 'test.permission.attach'))$$, '23505');
❌ Test Case: Reactivate a suspended user accountError: `1 test(s) failed:Test 7: User should remain not deleted after reactivation SELECT lives_ok($$INSERT INTO roles (id, name) VALUES (gen_random_uuid(), 'member')$$, 'Setup: insert role');
SELECT lives_ok($$INSERT INTO users (id, email, status, password_hash, is_deleted) VALUES (gen_random_uuid(), '[email protected]', 'suspended', 'hash', false)$$, 'Setup: insert suspended user');
SELECT lives_ok($$INSERT INTO user_roles (id, user_id, role_id) VALUES (gen_random_uuid(), (SELECT id FROM users WHERE email = '[email protected]'), (SELECT id FROM roles WHERE name = 'member'))$$, 'Setup: assign role to suspended user');
SELECT lives_ok($$INSERT INTO audit_logs (action, details, actor_id, target_user_id) VALUES ('user_status_changed', '{"from":"active","to":"suspended"}'::jsonb, NULL, (SELECT id FROM users WHERE email = '[email protected]'))$$, 'Setup: record suspension audit log');
SELECT lives_ok($$UPDATE users SET status = 'active', updated_at = now() WHERE email = '[email protected]' AND is_deleted = false$$, 'Attempt to reactivate suspended user');
SELECT is((SELECT status FROM users WHERE email = '[email protected]')::text, 'active'::text, 'User status should be active after reactivation');
SELECT ok((SELECT is_deleted FROM users WHERE email = '[email protected]'), 'User should remain not deleted after reactivation');
SELECT lives_ok($$INSERT INTO audit_logs (action, details, actor_id, target_user_id) VALUES ('user_status_changed', '{"from":"suspended","to":"active"}'::jsonb, NULL, (SELECT id FROM users WHERE email = '[email protected]'))$$, 'Record audit log for reactivation');
SELECT is((SELECT COUNT(*) FROM audit_logs WHERE action = 'user_status_changed' AND (details->> 'to') = 'active' AND target_user_id = (SELECT id FROM users WHERE email = '[email protected]')), 1::bigint, 'One audit log entry should record the reactivation');❌ Test Case: List only currently active (non-deleted) usersError: `4 test(s) failed:Test 5: active_users view should list only non-deleted users matching users where is_deleted = false SELECT lives_ok($$INSERT INTO users (email, password_hash, status, is_deleted, full_name) VALUES ('[email protected]', 'hash', 'active', false, 'Active One')$$, 'Setup: insert active user 1');
SELECT lives_ok($$INSERT INTO users (email, password_hash, status, is_deleted, full_name) VALUES ('[email protected]', 'hash', 'active', false, 'Active Two')$$, 'Setup: insert active user 2');
SELECT lives_ok($$INSERT INTO users (email, password_hash, status, is_deleted, full_name) VALUES ('[email protected]', 'hash', 'active', true, 'Deleted User')$$, 'Setup: insert soft-deleted user');
SELECT lives_ok($$INSERT INTO users (email, password_hash, status, is_deleted, full_name) VALUES ('[email protected]', 'hash', 'suspended', false, 'Suspended User')$$, 'Setup: insert suspended user');
SELECT results_eq($$SELECT id, email::text, status::text, full_name::text FROM active_users ORDER BY email$$, $$SELECT id, email::text, status::text, full_name::text FROM users WHERE is_deleted = false ORDER BY email$$, 'active_users view should list only non-deleted users matching users where is_deleted = false');
SELECT is((SELECT COUNT(*) FROM active_users), 3::bigint, 'active_users should contain three non-deleted users');
SELECT ok((SELECT COUNT(*) FROM active_users WHERE email = '[email protected]') = 0, 'deleted user must not appear in active_users');
SELECT ok((SELECT COUNT(*) FROM active_users WHERE status = 'active') = 2::bigint, 'active_users should include two users with status active');
SELECT ok((SELECT COUNT(*) FROM active_users WHERE status = 'suspended') = 1::bigint, 'active_users should include suspended users that are not deleted');❌ Test Case: Consume a password reset tokenError: `2 test(s) failed:Test 5: threw 23503 SELECT lives_ok($$INSERT INTO users (id, email, password_hash) VALUES (gen_random_uuid(), '[email protected]', 'hash')$$, 'Setup: create user');
SELECT lives_ok($$INSERT INTO password_reset_tokens (id, token, user_id, expires_at) VALUES (gen_random_uuid(), 'reset-token-123', (SELECT id FROM users WHERE email = '[email protected]'), NOW() + INTERVAL '1 hour')$$, 'Setup: create password reset token');
SELECT lives_ok($$UPDATE password_reset_tokens SET consumed_at = NOW() WHERE token = 'reset-token-123' AND expires_at > NOW() AND consumed_at IS NULL$$, 'Consume token should succeed when not expired and not consumed');
SELECT is((SELECT consumed_at IS NOT NULL FROM password_reset_tokens WHERE token = 'reset-token-123'), true, 'Token consumed_at should be set');
SELECT throws_ok($$UPDATE password_reset_tokens SET consumed_at = NOW() WHERE token = 'nonexistent-token' AND expires_at > NOW() AND consumed_at IS NULL$$, '23503');
SELECT lives_ok($$INSERT INTO password_reset_tokens (id, token, user_id, expires_at) VALUES (gen_random_uuid(), 'expired-token', (SELECT id FROM users WHERE email = '[email protected]'), NOW() - INTERVAL '1 hour')$$, 'Setup: insert expired token');
SELECT throws_ok($$UPDATE password_reset_tokens SET consumed_at = NOW() WHERE token = 'expired-token' AND expires_at > NOW() AND consumed_at IS NULL$$, '23514');❌ Test Case: Record an audit log for user status changeError:
|
This PR contains the following updates:
1.1.0->1.2.0GitHub Vulnerability Alerts
CVE-2025-66020
Summary
The
EMOJI_REGEXused in theemojiaction is vulnerable to a Regular Expression Denial of Service (ReDoS) attack. A short, maliciously crafted string (e.g., <100 characters) can cause the regex engine to consume excessive CPU time (minutes), leading to a Denial of Service (DoS) for the application.Details
The ReDoS vulnerability stems from "catastrophic backtracking" in the
EMOJI_REGEX. This is caused by ambiguity in the regex pattern due to overlapping character classes.Specifically, the class
\p{Emoji_Presentation}overlaps with more specific classes used in the same alternation, such as[\u{1F1E6}-\u{1F1FF}](regional indicator symbols used for flags) and\p{Emoji_Modifier_Base}.When the regex engine attempts to match a string that almost matches but ultimately fails (like the one in the PoC), this ambiguity forces it to explore an exponential number of possible paths. The matching time increases exponentially with the length of the crafted input, rather than linearly.
PoC
The following code demonstrates the vulnerability.
Impact
Any project using Valibot's
emojivalidation on user-controllable input is vulnerable to a Denial of Service attack.An attacker can block server resources (e.g., a web server's event loop) by submitting a short string to any endpoint that uses this validation. This is particularly dangerous because the attack string is short enough to bypass typical input length restrictions (e.g., maxLength(100)).
Recommended Fix
The root cause is the overlapping character classes. This can be resolved by making the alternatives mutually exclusive, typically by using negative lookaheads (
(?!...)) to subtract the specific classes from the more general one.The following modified
EMOJI_REGEXapplies this principle:Release Notes
open-circle/valibot (valibot)
v1.2.0Compare Source
Many thanks to @EskiMojo14, @makenowjust, @ysknsid25 and @jacekwilczynski for contributing to this release.
toBigint,toBoolean,toDate,toNumberandtoStringtransformation actions (pull request #1212)examplesaction to add example values to a schema (pull request #1199)getExamplesmethod to extract example values from a schema (pull request #1199)isbnvalidation action to validate ISBN-10 and ISBN-13 strings (pull request #1097)RawCheckAddIssue,RawCheckContext,RawCheckIssueInfo,RawTransformAddIssue,RawTransformContextandRawTransformIssueInfotypes for better developer experience withrawCheckandrawTransformactions (pull request #1359)EMOJI_REGEXused byemojiactionConfiguration
📅 Schedule: Branch creation - "" (UTC), Automerge - At any time (no schedule defined).
🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.
♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.
🔕 Ignore: Close this PR and you won't be reminded about this update again.
This PR was generated by Mend Renovate. View the repository job log.