#!/bin/bash # Script to test transaction immutability on active database (from .env) # This script safely tests database permissions without altering real data # # Tests: # 1. Can we INSERT into transactions? (should be allowed) # 2. Can we UPDATE transactions? (should be DENIED) # 3. Can we DELETE transactions? (should be DENIED) # # Safety: Uses database transactions with ROLLBACK to prevent any data changes set -e # Exit on error # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color echo -e "${BLUE}========================================${NC}" echo -e "${BLUE}Transaction Immutability Test${NC}" echo -e "${BLUE}========================================${NC}" echo "" # Get database credentials from .env if [ ! -f .env ]; then echo -e "${RED}Error: .env file not found${NC}" exit 1 fi DB_DATABASE=$(grep "^DB_DATABASE=" .env | cut -d '=' -f2 | sed 's/#.*//' | tr -d '"' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | sed 's/\r$//') DB_USERNAME=$(grep "^DB_USERNAME=" .env | cut -d '=' -f2 | sed 's/#.*//' | tr -d '"' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | sed 's/\r$//') DB_PASSWORD=$(grep "^DB_PASSWORD=" .env | cut -d '=' -f2- | sed 's/#.*//' | sed 's/^"//' | sed 's/"$//' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | sed 's/\r$//') DB_HOST=$(grep "^DB_HOST=" .env | cut -d '=' -f2 | sed 's/#.*//' | tr -d '"' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | sed 's/\r$//') # Default to localhost if not set if [ -z "$DB_HOST" ]; then DB_HOST="localhost" fi echo -e "${BLUE}Database:${NC} $DB_DATABASE" echo -e "${BLUE}User:${NC} $DB_USERNAME" echo -e "${BLUE}Host:${NC} $DB_HOST" echo "" # Check if mysql command is available if ! command -v mysql &> /dev/null; then echo -e "${RED}Error: mysql command not found${NC}" echo "Please install mysql-client" exit 1 fi # Test database connection echo -e "${YELLOW}Testing database connection...${NC}" if ! MYSQL_PWD="$DB_PASSWORD" mysql -h"$DB_HOST" -u"$DB_USERNAME" "$DB_DATABASE" -e "SELECT 1;" 2>/dev/null; then echo -e "${RED}Error: Cannot connect to database${NC}" echo -e "${YELLOW}Debug info:${NC}" echo -e " Database: $DB_DATABASE" echo -e " Username: $DB_USERNAME" echo -e " Host: $DB_HOST" exit 1 fi echo -e "${GREEN}✓ Database connection successful${NC}" echo "" # Get sample account IDs for testing echo -e "${YELLOW}Getting sample account IDs...${NC}" ACCOUNT_IDS=$(MYSQL_PWD="$DB_PASSWORD" mysql -h"$DB_HOST" -u"$DB_USERNAME" "$DB_DATABASE" -N -e "SELECT id FROM accounts LIMIT 2;") FROM_ACCOUNT=$(echo "$ACCOUNT_IDS" | head -n 1) TO_ACCOUNT=$(echo "$ACCOUNT_IDS" | tail -n 1) if [ -z "$FROM_ACCOUNT" ] || [ -z "$TO_ACCOUNT" ]; then echo -e "${RED}Error: Could not find sample accounts${NC}" exit 1 fi echo -e "${GREEN}✓ Using account IDs: $FROM_ACCOUNT → $TO_ACCOUNT${NC}" echo "" # Create a temporary test transaction ID variable TEST_TRANSACTION_ID="" # ==================== # TEST 1: INSERT (should be ALLOWED) # ==================== echo -e "${BLUE}========================================${NC}" echo -e "${BLUE}TEST 1: INSERT Permission${NC}" echo -e "${BLUE}========================================${NC}" MYSQL_PWD="$DB_PASSWORD" mysql -h"$DB_HOST" -u"$DB_USERNAME" "$DB_DATABASE" <&1 | tee /tmp/update_test.log START TRANSACTION; -- Try to update an existing transaction UPDATE transactions SET amount = 99999, description = 'IMMUTABILITY TEST - SHOULD BE BLOCKED' WHERE id = $EXISTING_ID; -- Check if update succeeded SELECT amount, description FROM transactions WHERE id = $EXISTING_ID; -- ROLLBACK for safety ROLLBACK; EOF UPDATE_RESULT=${PIPESTATUS[0]} # Verify the transaction was not modified CURRENT_AMOUNT=$(MYSQL_PWD="$DB_PASSWORD" mysql -h"$DB_HOST" -u"$DB_USERNAME" "$DB_DATABASE" -N -e "SELECT amount FROM transactions WHERE id = $EXISTING_ID;") if [ "$CURRENT_AMOUNT" != "$ORIGINAL_AMOUNT" ]; then echo -e "${RED}✗ UPDATE permission: ALLOWED (CRITICAL SECURITY ISSUE)${NC}" echo -e "${RED} Transaction amount was changed from $ORIGINAL_AMOUNT to $CURRENT_AMOUNT${NC}" echo -e "${RED} ⚠️ TRANSACTIONS ARE MUTABLE - THIS IS A CRITICAL FINANCIAL SECURITY ISSUE${NC}" elif grep -q "denied" /tmp/update_test.log 2>/dev/null; then echo -e "${GREEN}✓ UPDATE permission: DENIED${NC}" echo -e "${GREEN} Database user CANNOT modify transactions (secure)${NC}" else # Update command succeeded but amount unchanged (transaction rolled back) echo -e "${YELLOW}⚠ UPDATE permission: ALLOWED but transaction rolled back${NC}" echo -e "${YELLOW} Database user HAS UPDATE permission (potential security issue)${NC}" echo -e "${YELLOW} Data was not changed due to ROLLBACK${NC}" fi fi echo "" # ==================== # TEST 3: DELETE (should be DENIED) # ==================== echo -e "${BLUE}========================================${NC}" echo -e "${BLUE}TEST 3: DELETE Permission${NC}" echo -e "${BLUE}========================================${NC}" if [ -z "$EXISTING_ID" ]; then echo -e "${YELLOW}No existing transactions found, skipping DELETE test${NC}" DELETE_RESULT=1 else echo -e "Testing DELETE on transaction ID: $EXISTING_ID" # Verify transaction exists EXISTS_BEFORE=$(MYSQL_PWD="$DB_PASSWORD" mysql -h"$DB_HOST" -u"$DB_USERNAME" "$DB_DATABASE" -N -e "SELECT COUNT(*) FROM transactions WHERE id = $EXISTING_ID;") echo -e "Transaction exists: $EXISTS_BEFORE" # Try to delete (wrapped in transaction for safety) MYSQL_PWD="$DB_PASSWORD" mysql -h"$DB_HOST" -u"$DB_USERNAME" "$DB_DATABASE" <&1 | tee /tmp/delete_test.log START TRANSACTION; -- Try to delete an existing transaction DELETE FROM transactions WHERE id = $EXISTING_ID; -- Check if delete succeeded SELECT COUNT(*) as remaining FROM transactions WHERE id = $EXISTING_ID; -- ROLLBACK for safety ROLLBACK; EOF DELETE_RESULT=${PIPESTATUS[0]} # Verify the transaction still exists EXISTS_AFTER=$(MYSQL_PWD="$DB_PASSWORD" mysql -h"$DB_HOST" -u"$DB_USERNAME" "$DB_DATABASE" -N -e "SELECT COUNT(*) FROM transactions WHERE id = $EXISTING_ID;") if [ "$EXISTS_AFTER" != "$EXISTS_BEFORE" ]; then echo -e "${RED}✗ DELETE permission: ALLOWED (CRITICAL SECURITY ISSUE)${NC}" echo -e "${RED} Transaction was deleted${NC}" echo -e "${RED} ⚠️ TRANSACTIONS CAN BE DELETED - THIS IS A CRITICAL FINANCIAL SECURITY ISSUE${NC}" elif grep -q "denied" /tmp/delete_test.log 2>/dev/null; then echo -e "${GREEN}✓ DELETE permission: DENIED${NC}" echo -e "${GREEN} Database user CANNOT delete transactions (secure)${NC}" else # Delete command succeeded but transaction still exists (rolled back) echo -e "${YELLOW}⚠ DELETE permission: ALLOWED but transaction rolled back${NC}" echo -e "${YELLOW} Database user HAS DELETE permission (potential security issue)${NC}" echo -e "${YELLOW} Data was not changed due to ROLLBACK${NC}" fi fi echo "" # ==================== # FINAL SUMMARY # ==================== echo -e "${BLUE}========================================${NC}" echo -e "${BLUE}SUMMARY${NC}" echo -e "${BLUE}========================================${NC}" echo "" ISSUES_FOUND=0 if [ $INSERT_RESULT -eq 0 ]; then echo -e "${GREEN}✓ INSERT: ALLOWED (expected)${NC}" else echo -e "${RED}✗ INSERT: DENIED (unexpected - should be allowed)${NC}" ISSUES_FOUND=$((ISSUES_FOUND + 1)) fi # Check UPDATE test results if grep -q "denied" /tmp/update_test.log 2>/dev/null; then echo -e "${GREEN}✓ UPDATE: DENIED (expected - secure)${NC}" elif [ $UPDATE_RESULT -ne 0 ]; then echo -e "${GREEN}✓ UPDATE: DENIED (expected - secure)${NC}" else echo -e "${RED}✗ UPDATE: ALLOWED (security issue)${NC}" ISSUES_FOUND=$((ISSUES_FOUND + 1)) fi # Check DELETE test results if grep -q "denied" /tmp/delete_test.log 2>/dev/null; then echo -e "${GREEN}✓ DELETE: DENIED (expected - secure)${NC}" elif [ $DELETE_RESULT -ne 0 ]; then echo -e "${GREEN}✓ DELETE: DENIED (expected - secure)${NC}" else echo -e "${RED}✗ DELETE: ALLOWED (security issue)${NC}" ISSUES_FOUND=$((ISSUES_FOUND + 1)) fi echo "" if [ $ISSUES_FOUND -eq 0 ]; then echo -e "${GREEN}========================================${NC}" echo -e "${GREEN}✓ ALL TESTS PASSED${NC}" echo -e "${GREEN}Transaction immutability is properly enforced${NC}" echo -e "${GREEN}========================================${NC}" else echo -e "${RED}========================================${NC}" echo -e "${RED}✗ $ISSUES_FOUND SECURITY ISSUE(S) FOUND${NC}" echo -e "${RED}Transaction immutability is NOT properly enforced${NC}" echo -e "${RED}========================================${NC}" echo "" echo -e "${YELLOW}Recommended Fix:${NC}" echo -e "${YELLOW}REVOKE UPDATE, DELETE ON $DB_DATABASE.transactions FROM '$DB_USERNAME'@'$DB_HOST';${NC}" echo -e "${YELLOW}FLUSH PRIVILEGES;${NC}" fi echo "" echo -e "${BLUE}Note: All tests used database transactions with ROLLBACK${NC}" echo -e "${BLUE}No actual data was modified in the database${NC}" # Cleanup rm -f /tmp/update_test.log /tmp/delete_test.log exit $ISSUES_FOUND