@@ -561,6 +561,81 @@ def test_export_partition_feature_is_disabled(cluster):
561561 error = replica_with_export_disabled .query_and_get_error (f"KILL EXPORT PARTITION WHERE partition_id = '2020' and source_table = '{ mt_table } ' and destination_table = '{ s3_table } '" )
562562 assert "experimental" in error , "Expected error about disabled feature"
563563
564+
565+ def test_export_partition_permissions (cluster ):
566+ """Test that export partition validates permissions correctly:
567+ - User needs ALTER permission on source table
568+ - User needs INSERT permission on destination table
569+ """
570+ node = cluster .instances ["replica1" ]
571+
572+ mt_table = "permissions_mt_table"
573+ s3_table = "permissions_s3_table"
574+
575+ # Create tables as default user
576+ create_tables_and_insert_data (node , mt_table , s3_table , "replica1" )
577+
578+ # Create test users with specific permissions
579+ node .query ("CREATE USER IF NOT EXISTS user_no_alter IDENTIFIED WITH no_password" )
580+ node .query ("CREATE USER IF NOT EXISTS user_no_insert IDENTIFIED WITH no_password" )
581+ node .query ("CREATE USER IF NOT EXISTS user_with_permissions IDENTIFIED WITH no_password" )
582+
583+ # Grant basic access to all users
584+ node .query (f"GRANT SELECT ON { mt_table } TO user_no_alter" )
585+ node .query (f"GRANT SELECT ON { s3_table } TO user_no_alter" )
586+
587+ # user_no_insert has ALTER on source but no INSERT on destination
588+ node .query (f"GRANT ALTER ON { mt_table } TO user_no_insert" )
589+ node .query (f"GRANT SELECT ON { s3_table } TO user_no_insert" )
590+
591+ # user_with_permissions has both ALTER and INSERT
592+ node .query (f"GRANT ALTER ON { mt_table } TO user_with_permissions" )
593+ node .query (f"GRANT INSERT ON { s3_table } TO user_with_permissions" )
594+
595+ # Test 1: User without ALTER permission should fail
596+ error = node .query_and_get_error (
597+ f"ALTER TABLE { mt_table } EXPORT PARTITION ID '2020' TO TABLE { s3_table } "
598+ f"SETTINGS allow_experimental_export_merge_tree_part=1" ,
599+ user = "user_no_alter"
600+ )
601+ assert "ACCESS_DENIED" in error or "Not enough privileges" in error , \
602+ f"Expected ACCESS_DENIED error for user without ALTER, got: { error } "
603+
604+ # Test 2: User with ALTER but without INSERT permission should fail
605+ error = node .query_and_get_error (
606+ f"ALTER TABLE { mt_table } EXPORT PARTITION ID '2020' TO TABLE { s3_table } "
607+ f"SETTINGS allow_experimental_export_merge_tree_part=1" ,
608+ user = "user_no_insert"
609+ )
610+ assert "ACCESS_DENIED" in error or "Not enough privileges" in error , \
611+ f"Expected ACCESS_DENIED error for user without INSERT, got: { error } "
612+
613+ # Test 3: User with both ALTER and INSERT should succeed
614+ node .query (
615+ f"ALTER TABLE { mt_table } EXPORT PARTITION ID '2020' TO TABLE { s3_table } "
616+ f"SETTINGS allow_experimental_export_merge_tree_part=1" ,
617+ user = "user_with_permissions"
618+ )
619+
620+ # Wait for export to complete
621+ time .sleep (5 )
622+
623+ # Verify the export succeeded
624+ result = node .query (f"SELECT count() FROM { s3_table } WHERE year = 2020" )
625+ assert result .strip () == "3" , f"Expected 3 rows exported, got: { result } "
626+
627+ # Verify system table shows COMPLETED status
628+ status = node .query (
629+ f"""
630+ SELECT status FROM system.replicated_partition_exports
631+ WHERE source_table = '{ mt_table } '
632+ AND destination_table = '{ s3_table } '
633+ AND partition_id = '2020'
634+ """
635+ )
636+ assert status .strip () == "COMPLETED" , f"Expected COMPLETED status, got: { status } "
637+
638+
564639# def test_source_mutations_during_export_snapshot(cluster):
565640# node = cluster.instances["replica1"]
566641
0 commit comments