github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/libraries/doltcore/sqle/enginetest/privilege_test.go (about)

     1  // Copyright 2022 Dolthub, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package enginetest
    16  
    17  import (
    18  	"testing"
    19  
    20  	"github.com/dolthub/go-mysql-server/enginetest"
    21  	"github.com/dolthub/go-mysql-server/enginetest/queries"
    22  	"github.com/dolthub/go-mysql-server/enginetest/scriptgen/setup"
    23  	"github.com/dolthub/go-mysql-server/sql"
    24  	"github.com/dolthub/go-mysql-server/sql/mysql_db"
    25  	"github.com/dolthub/go-mysql-server/sql/plan"
    26  	"github.com/dolthub/go-mysql-server/sql/types"
    27  	"github.com/stretchr/testify/require"
    28  )
    29  
    30  var revisionDatabasePrivsSetupPostfix = []string{
    31  	"call dolt_commit('-Am', 'first commit')",
    32  	"call dolt_branch('b1')",
    33  	"use mydb/b1",
    34  }
    35  
    36  // The subset of tests in priv_auth_queries.go to run with alternate branch logic. Not all of them are suitable
    37  // because they are too difficult to adapt with simple additions to setup
    38  var revisionDatabasePrivilegeScriptNames = []string{
    39  	"Basic database and table name visibility",
    40  	"Basic SELECT and INSERT privilege checking",
    41  	"Table-level privileges exist",
    42  	"Basic revoke SELECT privilege",
    43  	"Basic revoke all global static privileges",
    44  	"Grant Role with SELECT Privilege",
    45  	"Revoke role currently granted to a user",
    46  	"Drop role currently granted to a user",
    47  	"Anonymous User",
    48  	"IPv4 Loopback == localhost",
    49  	"information_schema.columns table 'privileges' column gets correct values",
    50  	"basic tests on information_schema.SCHEMA_PRIVILEGES table",
    51  	"basic tests on information_schema.TABLE_PRIVILEGES table",
    52  }
    53  
    54  // TestRevisionDatabasePrivileges is a spot-check of privilege checking on the original privilege test scripts,
    55  // but with a revisioned database as the current db
    56  func TestRevisionDatabasePrivileges(t *testing.T) {
    57  	testsToRun := make(map[string]bool)
    58  	for _, name := range revisionDatabasePrivilegeScriptNames {
    59  		testsToRun[name] = true
    60  	}
    61  
    62  	var scripts []queries.UserPrivilegeTest
    63  	for _, script := range queries.UserPrivTests {
    64  		if testsToRun[script.Name] {
    65  			scripts = append(scripts, script)
    66  		}
    67  	}
    68  
    69  	require.Equal(t, len(scripts), len(testsToRun),
    70  		"Error in test setup: one or more expected tests not found. "+
    71  			"Did the name of a test change?")
    72  
    73  	for _, script := range scripts {
    74  		harness := newDoltHarness(t)
    75  		harness.configureStats = true
    76  		harness.Setup(setup.MydbData, setup.MytableData)
    77  		t.Run(script.Name, func(t *testing.T) {
    78  			engine := mustNewEngine(t, harness)
    79  			defer engine.Close()
    80  
    81  			ctx := enginetest.NewContext(harness)
    82  			ctx.NewCtxWithClient(sql.Client{
    83  				User:    "root",
    84  				Address: "localhost",
    85  			})
    86  			engine.EngineAnalyzer().Catalog.MySQLDb.AddRootAccount()
    87  			engine.EngineAnalyzer().Catalog.MySQLDb.SetPersister(&mysql_db.NoopPersister{})
    88  
    89  			for _, statement := range append(script.SetUpScript, revisionDatabasePrivsSetupPostfix...) {
    90  				if harness.SkipQueryTest(statement) {
    91  					t.Skip()
    92  				}
    93  				enginetest.RunQueryWithContext(t, engine, harness, ctx, statement)
    94  			}
    95  
    96  			for _, assertion := range script.Assertions {
    97  				if harness.SkipQueryTest(assertion.Query) {
    98  					t.Skipf("Skipping query %s", assertion.Query)
    99  				}
   100  
   101  				user := assertion.User
   102  				host := assertion.Host
   103  				if user == "" {
   104  					user = "root"
   105  				}
   106  				if host == "" {
   107  					host = "localhost"
   108  				}
   109  				ctx := enginetest.NewContextWithClient(harness, sql.Client{
   110  					User:    user,
   111  					Address: host,
   112  				})
   113  				ctx.SetCurrentDatabase("mydb/b1")
   114  
   115  				if assertion.ExpectedErr != nil {
   116  					t.Run(assertion.Query, func(t *testing.T) {
   117  						enginetest.AssertErrWithCtx(t, engine, harness, ctx, assertion.Query, assertion.ExpectedErr)
   118  					})
   119  				} else if assertion.ExpectedErrStr != "" {
   120  					t.Run(assertion.Query, func(t *testing.T) {
   121  						enginetest.AssertErrWithCtx(t, engine, harness, ctx, assertion.Query, nil, assertion.ExpectedErrStr)
   122  					})
   123  				} else {
   124  					t.Run(assertion.Query, func(t *testing.T) {
   125  						enginetest.TestQueryWithContext(t, ctx, engine, harness, assertion.Query, assertion.Expected, nil, nil)
   126  					})
   127  				}
   128  			}
   129  		})
   130  	}
   131  }
   132  
   133  // Privilege test scripts for revision databases. Due to limitations in test construction, test assertions are always
   134  // performed with current db = mydb/b1, write scripts accordingly
   135  var DoltOnlyRevisionDbPrivilegeTests = []queries.UserPrivilegeTest{
   136  	{
   137  		Name: "Basic database and table name visibility",
   138  		SetUpScript: []string{
   139  			"use mydb",
   140  			"CREATE TABLE test (pk BIGINT PRIMARY KEY);",
   141  			"INSERT INTO test VALUES (1);",
   142  			"call dolt_commit('-Am', 'first commit')",
   143  			"call dolt_branch('b1')",
   144  			"use mydb/b1",
   145  			"CREATE USER tester@localhost;",
   146  			"CREATE ROLE test_role;",
   147  			"GRANT SELECT ON mydb.* TO test_role;",
   148  		},
   149  		Assertions: []queries.UserPrivilegeTestAssertion{
   150  			{
   151  				User:        "tester",
   152  				Host:        "localhost",
   153  				Query:       "SELECT * FROM test;/*1*/",
   154  				ExpectedErr: sql.ErrDatabaseAccessDeniedForUser,
   155  			},
   156  			{
   157  				User:        "tester",
   158  				Host:        "localhost",
   159  				Query:       "SELECT * FROM test2;/*1*/",
   160  				ExpectedErr: sql.ErrDatabaseAccessDeniedForUser,
   161  			},
   162  			{
   163  				User:     "root",
   164  				Host:     "localhost",
   165  				Query:    "GRANT SELECT ON mydb.* TO tester@localhost;",
   166  				Expected: []sql.Row{{types.NewOkResult(0)}},
   167  			},
   168  			{
   169  				User:     "tester",
   170  				Host:     "localhost",
   171  				Query:    "SELECT * FROM test;/*2*/",
   172  				Expected: []sql.Row{{1}},
   173  			},
   174  			{
   175  				User:        "tester",
   176  				Host:        "localhost",
   177  				Query:       "SELECT * FROM test2;/*2*/",
   178  				ExpectedErr: sql.ErrTableNotFound,
   179  			},
   180  			{
   181  				User:     "root",
   182  				Host:     "localhost",
   183  				Query:    "REVOKE SELECT ON mydb.* FROM tester@localhost;",
   184  				Expected: []sql.Row{{types.NewOkResult(0)}},
   185  			},
   186  			{ // Ensure we've reverted to initial state (all SELECTs after REVOKEs are doing this)
   187  				User:        "tester",
   188  				Host:        "localhost",
   189  				Query:       "SELECT * FROM test;/*3*/",
   190  				ExpectedErr: sql.ErrDatabaseAccessDeniedForUser,
   191  			},
   192  			{
   193  				User:        "tester",
   194  				Host:        "localhost",
   195  				Query:       "SELECT * FROM test2;/*3*/",
   196  				ExpectedErr: sql.ErrDatabaseAccessDeniedForUser,
   197  			},
   198  			{
   199  				User:     "root",
   200  				Host:     "localhost",
   201  				Query:    "GRANT SELECT ON mydb.* TO tester@localhost;",
   202  				Expected: []sql.Row{{types.NewOkResult(0)}},
   203  			},
   204  			{
   205  				User:     "tester",
   206  				Host:     "localhost",
   207  				Query:    "SELECT * FROM mydb.test;/*4*/",
   208  				Expected: []sql.Row{{1}},
   209  			},
   210  			{
   211  				User:        "tester",
   212  				Host:        "localhost",
   213  				Query:       "SELECT * FROM test2;/*4*/",
   214  				ExpectedErr: sql.ErrTableNotFound,
   215  			},
   216  			{
   217  				User:     "root",
   218  				Host:     "localhost",
   219  				Query:    "REVOKE SELECT ON mydb.* FROM tester@localhost;",
   220  				Expected: []sql.Row{{types.NewOkResult(0)}},
   221  			},
   222  			{
   223  				User:        "tester",
   224  				Host:        "localhost",
   225  				Query:       "SELECT * FROM test;/*5*/",
   226  				ExpectedErr: sql.ErrDatabaseAccessDeniedForUser,
   227  			},
   228  			{
   229  				User:        "tester",
   230  				Host:        "localhost",
   231  				Query:       "SELECT * FROM test2;/*5*/",
   232  				ExpectedErr: sql.ErrDatabaseAccessDeniedForUser,
   233  			},
   234  			{
   235  				User:     "root",
   236  				Host:     "localhost",
   237  				Query:    "GRANT SELECT ON mydb.test TO tester@localhost;",
   238  				Expected: []sql.Row{{types.NewOkResult(0)}},
   239  			},
   240  			{
   241  				User:     "tester",
   242  				Host:     "localhost",
   243  				Query:    "SELECT * FROM test;/*6*/",
   244  				Expected: []sql.Row{{1}},
   245  			},
   246  			{
   247  				User:        "tester",
   248  				Host:        "localhost",
   249  				Query:       "SELECT * FROM test2;/*6*/",
   250  				ExpectedErr: sql.ErrTableAccessDeniedForUser,
   251  			},
   252  			{
   253  				User:     "root",
   254  				Host:     "localhost",
   255  				Query:    "REVOKE SELECT ON mydb.test FROM tester@localhost;",
   256  				Expected: []sql.Row{{types.NewOkResult(0)}},
   257  			},
   258  			{
   259  				User:        "tester",
   260  				Host:        "localhost",
   261  				Query:       "SELECT * FROM test;/*7*/",
   262  				ExpectedErr: sql.ErrDatabaseAccessDeniedForUser,
   263  			},
   264  			{
   265  				User:        "tester",
   266  				Host:        "localhost",
   267  				Query:       "SELECT * FROM test2;/*7*/",
   268  				ExpectedErr: sql.ErrDatabaseAccessDeniedForUser,
   269  			},
   270  			{
   271  				User:     "root",
   272  				Host:     "localhost",
   273  				Query:    "GRANT SELECT ON mydb.test2 TO tester@localhost;",
   274  				Expected: []sql.Row{{types.NewOkResult(0)}},
   275  			},
   276  			{
   277  				User:        "tester",
   278  				Host:        "localhost",
   279  				Query:       "SELECT * FROM test;/*8*/",
   280  				ExpectedErr: sql.ErrTableAccessDeniedForUser,
   281  			},
   282  			{
   283  				User:        "tester",
   284  				Host:        "localhost",
   285  				Query:       "SELECT * FROM test2;/*8*/",
   286  				ExpectedErr: sql.ErrTableNotFound,
   287  			},
   288  			{
   289  				User:     "root",
   290  				Host:     "localhost",
   291  				Query:    "REVOKE SELECT ON mydb.test2 FROM tester@localhost;",
   292  				Expected: []sql.Row{{types.NewOkResult(0)}},
   293  			},
   294  			{
   295  				User:        "tester",
   296  				Host:        "localhost",
   297  				Query:       "SELECT * FROM test;/*9*/",
   298  				ExpectedErr: sql.ErrDatabaseAccessDeniedForUser,
   299  			},
   300  			{
   301  				User:        "tester",
   302  				Host:        "localhost",
   303  				Query:       "SELECT * FROM test2;/*9*/",
   304  				ExpectedErr: sql.ErrDatabaseAccessDeniedForUser,
   305  			},
   306  			{
   307  				User:     "root",
   308  				Host:     "localhost",
   309  				Query:    "GRANT test_role TO tester@localhost;",
   310  				Expected: []sql.Row{{types.NewOkResult(0)}},
   311  			},
   312  			{
   313  				User:     "tester",
   314  				Host:     "localhost",
   315  				Query:    "SELECT * FROM test;/*10*/",
   316  				Expected: []sql.Row{{1}},
   317  			},
   318  			{
   319  				User:        "tester",
   320  				Host:        "localhost",
   321  				Query:       "SELECT * FROM test2;/*10*/",
   322  				ExpectedErr: sql.ErrTableNotFound,
   323  			},
   324  		},
   325  	},
   326  	{
   327  		Name: "Basic SELECT and INSERT privilege checking",
   328  		SetUpScript: []string{
   329  			"CREATE TABLE test (pk BIGINT PRIMARY KEY);",
   330  			"INSERT INTO test VALUES (1), (2), (3);",
   331  			"call dolt_commit('-Am', 'first commit');",
   332  			"call dolt_branch('b1')",
   333  			"use mydb/b1;",
   334  			"CREATE USER tester@localhost;",
   335  		},
   336  		Assertions: []queries.UserPrivilegeTestAssertion{
   337  			{
   338  				User:        "tester",
   339  				Host:        "localhost",
   340  				Query:       "INSERT INTO test VALUES (4);",
   341  				ExpectedErr: sql.ErrDatabaseAccessDeniedForUser,
   342  			},
   343  			{
   344  				User:     "root",
   345  				Host:     "localhost",
   346  				Query:    "GRANT INSERT ON mydb.* TO tester@localhost;",
   347  				Expected: []sql.Row{{types.NewOkResult(0)}},
   348  			},
   349  			{
   350  				User:     "tester",
   351  				Host:     "localhost",
   352  				Query:    "INSERT INTO test VALUES (4);",
   353  				Expected: []sql.Row{{types.NewOkResult(1)}},
   354  			},
   355  			{
   356  				User:        "tester",
   357  				Host:        "localhost",
   358  				Query:       "SELECT * FROM test;",
   359  				ExpectedErr: sql.ErrPrivilegeCheckFailed,
   360  			},
   361  			{
   362  				User:     "root",
   363  				Host:     "localhost",
   364  				Query:    "SELECT * FROM test;",
   365  				Expected: []sql.Row{{1}, {2}, {3}, {4}},
   366  			},
   367  			{
   368  				User:     "root",
   369  				Host:     "localhost",
   370  				Query:    "GRANT SELECT ON mydb.* TO tester@localhost;",
   371  				Expected: []sql.Row{{types.NewOkResult(0)}},
   372  			},
   373  			{
   374  				User:     "tester",
   375  				Host:     "localhost",
   376  				Query:    "SELECT * FROM test;",
   377  				Expected: []sql.Row{{1}, {2}, {3}, {4}},
   378  			},
   379  		},
   380  	},
   381  	{
   382  		Name: "Basic UPDATE privilege checking",
   383  		SetUpScript: []string{
   384  			"CREATE TABLE test (pk BIGINT PRIMARY KEY);",
   385  			"INSERT INTO test VALUES (1), (2), (3);",
   386  			"call dolt_commit('-Am', 'first commit');",
   387  			"call dolt_branch('b1')",
   388  			"use mydb/b1;",
   389  			"CREATE USER tester@localhost;",
   390  		},
   391  		Assertions: []queries.UserPrivilegeTestAssertion{
   392  			{
   393  				User:        "tester",
   394  				Host:        "localhost",
   395  				Query:       "UPDATE test set pk = 4 where pk = 3;",
   396  				ExpectedErr: sql.ErrDatabaseAccessDeniedForUser,
   397  			},
   398  			{
   399  				User:     "root",
   400  				Host:     "localhost",
   401  				Query:    "GRANT UPDATE ON mydb.* TO tester@localhost;",
   402  				Expected: []sql.Row{{types.NewOkResult(0)}},
   403  			},
   404  			{
   405  				User:        "tester",
   406  				Host:        "localhost",
   407  				Query:       "INSERT INTO test VALUES (4);",
   408  				ExpectedErr: sql.ErrPrivilegeCheckFailed,
   409  			},
   410  			{
   411  				User:  "tester",
   412  				Host:  "localhost",
   413  				Query: "UPDATE test set pk = 4 where pk = 3;",
   414  				Expected: []sql.Row{{types.OkResult{
   415  					RowsAffected: 1,
   416  					Info: plan.UpdateInfo{
   417  						Matched: 1,
   418  						Updated: 1,
   419  					},
   420  				}}},
   421  			},
   422  			{
   423  				User:        "tester",
   424  				Host:        "localhost",
   425  				Query:       "SELECT * FROM test;",
   426  				ExpectedErr: sql.ErrPrivilegeCheckFailed,
   427  			},
   428  			{
   429  				User:     "root",
   430  				Host:     "localhost",
   431  				Query:    "SELECT * FROM test;",
   432  				Expected: []sql.Row{{1}, {2}, {4}},
   433  			},
   434  		},
   435  	},
   436  	{
   437  		Name: "Basic DELETE privilege checking",
   438  		SetUpScript: []string{
   439  			"CREATE TABLE test (pk BIGINT PRIMARY KEY);",
   440  			"INSERT INTO test VALUES (1), (2), (3);",
   441  			"call dolt_commit('-Am', 'first commit');",
   442  			"call dolt_branch('b1')",
   443  			"use mydb/b1;",
   444  			"CREATE USER tester@localhost;",
   445  		},
   446  		Assertions: []queries.UserPrivilegeTestAssertion{
   447  			{
   448  				User:        "tester",
   449  				Host:        "localhost",
   450  				Query:       "DELETE from test where pk = 3;",
   451  				ExpectedErr: sql.ErrDatabaseAccessDeniedForUser,
   452  			},
   453  			{
   454  				User:     "root",
   455  				Host:     "localhost",
   456  				Query:    "GRANT DELETE ON mydb.* TO tester@localhost;",
   457  				Expected: []sql.Row{{types.NewOkResult(0)}},
   458  			},
   459  			{
   460  				User:        "tester",
   461  				Host:        "localhost",
   462  				Query:       "INSERT INTO test VALUES (4);",
   463  				ExpectedErr: sql.ErrPrivilegeCheckFailed,
   464  			},
   465  			{
   466  				User:     "tester",
   467  				Host:     "localhost",
   468  				Query:    "DELETE from test where pk = 3;",
   469  				Expected: []sql.Row{{types.NewOkResult(1)}},
   470  			},
   471  			{
   472  				User:        "tester",
   473  				Host:        "localhost",
   474  				Query:       "SELECT * FROM test;",
   475  				ExpectedErr: sql.ErrPrivilegeCheckFailed,
   476  			},
   477  			{
   478  				User:     "root",
   479  				Host:     "localhost",
   480  				Query:    "SELECT * FROM test;",
   481  				Expected: []sql.Row{{1}, {2}},
   482  			},
   483  		},
   484  	},
   485  	{
   486  		Name: "Basic CREATE TABLE privilege checking",
   487  		SetUpScript: []string{
   488  			"CREATE TABLE test (pk BIGINT PRIMARY KEY);",
   489  			"call dolt_commit('-Am', 'first commit');",
   490  			"call dolt_branch('b1')",
   491  			"use mydb/b1;",
   492  			"CREATE USER tester@localhost;",
   493  		},
   494  		Assertions: []queries.UserPrivilegeTestAssertion{
   495  			{
   496  				User:        "tester",
   497  				Host:        "localhost",
   498  				Query:       "CREATE TABLE t2 (a int primary key);",
   499  				ExpectedErr: sql.ErrDatabaseAccessDeniedForUser,
   500  			},
   501  			{
   502  				User:     "root",
   503  				Host:     "localhost",
   504  				Query:    "GRANT CREATE ON mydb.* TO tester@localhost;",
   505  				Expected: []sql.Row{{types.NewOkResult(0)}},
   506  			},
   507  			{
   508  				User:     "tester",
   509  				Host:     "localhost",
   510  				Query:    "CREATE TABLE t2 (a int primary key);",
   511  				Expected: []sql.Row{{types.NewOkResult(0)}},
   512  			},
   513  			{
   514  				User:     "tester",
   515  				Host:     "localhost",
   516  				Query:    "show tables;",
   517  				Expected: []sql.Row{{"mytable"}, {"myview"}, {"test"}, {"t2"}},
   518  			},
   519  		},
   520  	},
   521  	{
   522  		Name: "Basic DROP TABLE privilege checking",
   523  		SetUpScript: []string{
   524  			"CREATE TABLE test (pk BIGINT PRIMARY KEY);",
   525  			"INSERT INTO test VALUES (1), (2), (3);",
   526  			"call dolt_commit('-Am', 'first commit');",
   527  			"call dolt_branch('b1')",
   528  			"use mydb/b1;",
   529  			"CREATE USER tester@localhost;",
   530  		},
   531  		Assertions: []queries.UserPrivilegeTestAssertion{
   532  			{
   533  				User:        "tester",
   534  				Host:        "localhost",
   535  				Query:       "DROP TABLE test;",
   536  				ExpectedErr: sql.ErrDatabaseAccessDeniedForUser,
   537  			},
   538  			{
   539  				User:     "root",
   540  				Host:     "localhost",
   541  				Query:    "GRANT DROP ON mydb.* TO tester@localhost;",
   542  				Expected: []sql.Row{{types.NewOkResult(0)}},
   543  			},
   544  			{
   545  				User:     "tester",
   546  				Host:     "localhost",
   547  				Query:    "DROP TABLE TEST",
   548  				Expected: []sql.Row{{types.NewOkResult(0)}},
   549  			},
   550  			{
   551  				User:     "tester",
   552  				Host:     "localhost",
   553  				Query:    "show tables;",
   554  				Expected: []sql.Row{{"mytable"}, {"myview"}},
   555  			},
   556  		},
   557  	},
   558  	{
   559  		Name: "Basic ALTER TABLE privilege checking",
   560  		SetUpScript: []string{
   561  			"CREATE TABLE test (pk BIGINT PRIMARY KEY);",
   562  			"INSERT INTO test VALUES (1), (2), (3);",
   563  			"call dolt_commit('-Am', 'first commit');",
   564  			"call dolt_branch('b1')",
   565  			"use mydb/b1;",
   566  			"CREATE USER tester@localhost;",
   567  		},
   568  		Assertions: []queries.UserPrivilegeTestAssertion{
   569  			{
   570  				User:        "tester",
   571  				Host:        "localhost",
   572  				Query:       "ALTER TABLE test add column a int;",
   573  				ExpectedErr: sql.ErrDatabaseAccessDeniedForUser,
   574  			},
   575  			{
   576  				User:     "root",
   577  				Host:     "localhost",
   578  				Query:    "GRANT ALTER ON mydb.* TO tester@localhost;",
   579  				Expected: []sql.Row{{types.NewOkResult(0)}},
   580  			},
   581  			{
   582  				User:     "tester",
   583  				Host:     "localhost",
   584  				Query:    "ALTER TABLE test add column a int;",
   585  				Expected: []sql.Row{{types.NewOkResult(0)}},
   586  			},
   587  			{
   588  				User:  "tester",
   589  				Host:  "localhost",
   590  				Query: "desc test;",
   591  				Expected: []sql.Row{
   592  					{"pk", "bigint", "NO", "PRI", nil, ""},
   593  					{"a", "int", "YES", "", nil, ""},
   594  				},
   595  			},
   596  		},
   597  	},
   598  	{
   599  		Name: "Basic INDEX privilege checking",
   600  		SetUpScript: []string{
   601  			"CREATE TABLE test (pk BIGINT PRIMARY KEY, a int);",
   602  			"INSERT INTO test VALUES (1,1), (2,2), (3,3);",
   603  			"call dolt_commit('-Am', 'first commit');",
   604  			"call dolt_branch('b1')",
   605  			"use mydb/b1;",
   606  			"CREATE USER tester@localhost;",
   607  		},
   608  		Assertions: []queries.UserPrivilegeTestAssertion{
   609  			{
   610  				User:        "tester",
   611  				Host:        "localhost",
   612  				Query:       "create index t1 on test(a) ;",
   613  				ExpectedErr: sql.ErrDatabaseAccessDeniedForUser,
   614  			},
   615  			{
   616  				User:     "root",
   617  				Host:     "localhost",
   618  				Query:    "GRANT select ON mydb.* TO tester@localhost;",
   619  				Expected: []sql.Row{{types.NewOkResult(0)}},
   620  			},
   621  			{
   622  				User:        "tester",
   623  				Host:        "localhost",
   624  				Query:       "create index t1 on test(a) ;",
   625  				ExpectedErr: sql.ErrPrivilegeCheckFailed,
   626  			},
   627  			{
   628  				User:     "root",
   629  				Host:     "localhost",
   630  				Query:    "GRANT index ON mydb.* TO tester@localhost;",
   631  				Expected: []sql.Row{{types.NewOkResult(0)}},
   632  			},
   633  			{
   634  				User:     "tester",
   635  				Host:     "localhost",
   636  				Query:    "create index t1 on test(a) ;",
   637  				Expected: []sql.Row{{types.NewOkResult(0)}},
   638  			},
   639  			{
   640  				User:  "tester",
   641  				Host:  "localhost",
   642  				Query: "desc test;",
   643  				Expected: []sql.Row{
   644  					{"pk", "bigint", "NO", "PRI", nil, ""},
   645  					{"a", "int", "YES", "MUL", nil, ""},
   646  				},
   647  			},
   648  			{
   649  				User:     "root",
   650  				Host:     "localhost",
   651  				Query:    "REVOKE index ON mydb.* FROM tester@localhost;",
   652  				Expected: []sql.Row{{types.NewOkResult(0)}},
   653  			},
   654  			{
   655  				User:        "tester",
   656  				Host:        "localhost",
   657  				Query:       "drop index t1 on test;",
   658  				ExpectedErr: sql.ErrPrivilegeCheckFailed,
   659  			},
   660  			{
   661  				User:     "root",
   662  				Host:     "localhost",
   663  				Query:    "GRANT index ON mydb.* TO tester@localhost;",
   664  				Expected: []sql.Row{{types.NewOkResult(0)}},
   665  			},
   666  			{
   667  				User:     "tester",
   668  				Host:     "localhost",
   669  				Query:    "drop index t1 on test;",
   670  				Expected: []sql.Row{{types.NewOkResult(0)}},
   671  			},
   672  			{
   673  				User:  "tester",
   674  				Host:  "localhost",
   675  				Query: "desc test;",
   676  				Expected: []sql.Row{
   677  					{"pk", "bigint", "NO", "PRI", nil, ""},
   678  					{"a", "int", "YES", "", nil, ""},
   679  				},
   680  			},
   681  		},
   682  	},
   683  	{
   684  		Name: "Basic constraint privilege checking",
   685  		SetUpScript: []string{
   686  			"CREATE TABLE test (pk BIGINT PRIMARY KEY, a int);",
   687  			"INSERT INTO test VALUES (1,1), (2,2), (3,3);",
   688  			"call dolt_commit('-Am', 'first commit');",
   689  			"call dolt_branch('b1')",
   690  			"use mydb/b1;",
   691  			"CREATE USER tester@localhost;",
   692  		},
   693  		Assertions: []queries.UserPrivilegeTestAssertion{
   694  			{
   695  				User:        "tester",
   696  				Host:        "localhost",
   697  				Query:       "alter table test add constraint CHECK (NULL = NULL);",
   698  				ExpectedErr: sql.ErrDatabaseAccessDeniedForUser,
   699  			},
   700  			{
   701  				User:     "root",
   702  				Host:     "localhost",
   703  				Query:    "GRANT select ON mydb.* TO tester@localhost;",
   704  				Expected: []sql.Row{{types.NewOkResult(0)}},
   705  			},
   706  			{
   707  				User:        "tester",
   708  				Host:        "localhost",
   709  				Query:       "alter table test add constraint CHECK (NULL = NULL);",
   710  				ExpectedErr: sql.ErrPrivilegeCheckFailed,
   711  			},
   712  			{
   713  				User:     "root",
   714  				Host:     "localhost",
   715  				Query:    "GRANT alter ON mydb.* TO tester@localhost;",
   716  				Expected: []sql.Row{{types.NewOkResult(0)}},
   717  			},
   718  			{
   719  				User:     "tester",
   720  				Host:     "localhost",
   721  				Query:    "alter table test add constraint chk1 CHECK (a < 10);",
   722  				Expected: []sql.Row{{types.NewOkResult(0)}},
   723  			},
   724  			{
   725  				User:  "tester",
   726  				Host:  "localhost",
   727  				Query: "show create table test;",
   728  				Expected: []sql.Row{
   729  					{"test", "CREATE TABLE `test` (\n" +
   730  						"  `pk` bigint NOT NULL,\n" +
   731  						"  `a` int,\n" +
   732  						"  PRIMARY KEY (`pk`),\n" +
   733  						"  CONSTRAINT `chk1` CHECK ((`a` < 10))\n" +
   734  						") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"},
   735  				},
   736  			},
   737  			{
   738  				User:     "root",
   739  				Host:     "localhost",
   740  				Query:    "REVOKE alter ON mydb.* FROM tester@localhost;",
   741  				Expected: []sql.Row{{types.NewOkResult(0)}},
   742  			},
   743  			{
   744  				User:        "tester",
   745  				Host:        "localhost",
   746  				Query:       "alter table test drop check chk1;",
   747  				ExpectedErr: sql.ErrPrivilegeCheckFailed,
   748  			},
   749  			{
   750  				User:     "root",
   751  				Host:     "localhost",
   752  				Query:    "GRANT alter ON mydb.* TO tester@localhost;",
   753  				Expected: []sql.Row{{types.NewOkResult(0)}},
   754  			},
   755  			{
   756  				User:     "tester",
   757  				Host:     "localhost",
   758  				Query:    "alter table test drop check chk1;",
   759  				Expected: []sql.Row{},
   760  			},
   761  			{
   762  				User:  "tester",
   763  				Host:  "localhost",
   764  				Query: "show create table test;",
   765  				Expected: []sql.Row{
   766  					{"test", "CREATE TABLE `test` (\n" +
   767  						"  `pk` bigint NOT NULL,\n" +
   768  						"  `a` int,\n" +
   769  						"  PRIMARY KEY (`pk`)\n" +
   770  						") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"},
   771  				},
   772  			},
   773  			{
   774  				User:     "tester",
   775  				Host:     "localhost",
   776  				Query:    "alter table test add constraint chk1 CHECK (a < 10);",
   777  				Expected: []sql.Row{{types.NewOkResult(0)}},
   778  			},
   779  			{
   780  				User:     "root",
   781  				Host:     "localhost",
   782  				Query:    "REVOKE alter ON mydb.* FROM tester@localhost;",
   783  				Expected: []sql.Row{{types.NewOkResult(0)}},
   784  			},
   785  			{
   786  				User:        "tester",
   787  				Host:        "localhost",
   788  				Query:       "alter table test drop constraint chk1;",
   789  				ExpectedErr: sql.ErrPrivilegeCheckFailed,
   790  			},
   791  			{
   792  				User:     "root",
   793  				Host:     "localhost",
   794  				Query:    "GRANT alter ON mydb.* TO tester@localhost;",
   795  				Expected: []sql.Row{{types.NewOkResult(0)}},
   796  			},
   797  			{
   798  				User:     "tester",
   799  				Host:     "localhost",
   800  				Query:    "alter table test drop constraint chk1;",
   801  				Expected: []sql.Row{},
   802  			},
   803  			{
   804  				User:  "tester",
   805  				Host:  "localhost",
   806  				Query: "show create table test;",
   807  				Expected: []sql.Row{
   808  					{"test", "CREATE TABLE `test` (\n" +
   809  						"  `pk` bigint NOT NULL,\n" +
   810  						"  `a` int,\n" +
   811  						"  PRIMARY KEY (`pk`)\n" +
   812  						") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"},
   813  				},
   814  			},
   815  		},
   816  	},
   817  	{
   818  		Name: "Basic revoke SELECT privilege",
   819  		SetUpScript: []string{
   820  			"CREATE TABLE test (pk BIGINT PRIMARY KEY);",
   821  			"INSERT INTO test VALUES (1), (2), (3);",
   822  			"call dolt_commit('-Am', 'first commit');",
   823  			"call dolt_branch('b1')",
   824  			"use mydb/b1;",
   825  			"CREATE USER tester@localhost;",
   826  			"GRANT SELECT ON mydb.* TO tester@localhost;",
   827  		},
   828  		Assertions: []queries.UserPrivilegeTestAssertion{
   829  			{
   830  				User:     "tester",
   831  				Host:     "localhost",
   832  				Query:    "SELECT * FROM test;",
   833  				Expected: []sql.Row{{1}, {2}, {3}},
   834  			},
   835  			{
   836  				User:     "root",
   837  				Host:     "localhost",
   838  				Query:    "SELECT User, Host, Select_priv FROM mysql.user WHERE User = 'tester';",
   839  				Expected: []sql.Row{{"tester", "localhost", "N"}},
   840  			},
   841  			{
   842  				User:     "root",
   843  				Host:     "localhost",
   844  				Query:    "REVOKE SELECT ON mydb.* FROM tester@localhost;",
   845  				Expected: []sql.Row{{types.NewOkResult(0)}},
   846  			},
   847  			{
   848  				User:        "tester",
   849  				Host:        "localhost",
   850  				Query:       "SELECT * FROM test;",
   851  				ExpectedErr: sql.ErrDatabaseAccessDeniedForUser,
   852  			},
   853  			{
   854  				User:     "root",
   855  				Host:     "localhost",
   856  				Query:    "SELECT User, Host, Select_priv FROM mysql.user WHERE User = 'tester';",
   857  				Expected: []sql.Row{{"tester", "localhost", "N"}},
   858  			},
   859  		},
   860  	},
   861  	{
   862  		Name: "Grant Role with SELECT Privilege",
   863  		SetUpScript: []string{
   864  			"SET @@GLOBAL.activate_all_roles_on_login = true;",
   865  			"CREATE TABLE test (pk BIGINT PRIMARY KEY);",
   866  			"INSERT INTO test VALUES (1), (2), (3);",
   867  			"call dolt_commit('-Am', 'first commit');",
   868  			"call dolt_branch('b1')",
   869  			"use mydb/b1;",
   870  			"CREATE USER tester@localhost;",
   871  			"CREATE ROLE test_role;",
   872  			"GRANT SELECT ON mydb.* TO test_role;",
   873  		},
   874  		Assertions: []queries.UserPrivilegeTestAssertion{
   875  			{
   876  				User:        "tester",
   877  				Host:        "localhost",
   878  				Query:       "SELECT * FROM test;",
   879  				ExpectedErr: sql.ErrDatabaseAccessDeniedForUser,
   880  			},
   881  			{
   882  				User:     "root",
   883  				Host:     "localhost",
   884  				Query:    "SELECT COUNT(*) FROM mysql.role_edges;",
   885  				Expected: []sql.Row{{0}},
   886  			},
   887  			{
   888  				User:     "root",
   889  				Host:     "localhost",
   890  				Query:    "GRANT test_role TO tester@localhost;",
   891  				Expected: []sql.Row{{types.NewOkResult(0)}},
   892  			},
   893  			{
   894  				User:     "root",
   895  				Host:     "localhost",
   896  				Query:    "SELECT * FROM mysql.role_edges;",
   897  				Expected: []sql.Row{{"%", "test_role", "localhost", "tester", "N"}},
   898  			},
   899  			{
   900  				User:     "tester",
   901  				Host:     "localhost",
   902  				Query:    "SELECT * FROM test;",
   903  				Expected: []sql.Row{{1}, {2}, {3}},
   904  			},
   905  			{
   906  				User:     "root",
   907  				Host:     "localhost",
   908  				Query:    "SELECT User, Host, Select_priv FROM mysql.user WHERE User = 'tester';",
   909  				Expected: []sql.Row{{"tester", "localhost", "N"}},
   910  			},
   911  		},
   912  	},
   913  	{
   914  		Name: "Revoke role currently granted to a user",
   915  		SetUpScript: []string{
   916  			"SET @@GLOBAL.activate_all_roles_on_login = true;",
   917  			"CREATE TABLE test (pk BIGINT PRIMARY KEY);",
   918  			"INSERT INTO test VALUES (1), (2), (3);",
   919  			"call dolt_commit('-Am', 'first commit');",
   920  			"call dolt_branch('b1')",
   921  			"use mydb/b1;",
   922  			"CREATE USER tester@localhost;",
   923  			"CREATE ROLE test_role;",
   924  			"GRANT SELECT ON mydb.* TO test_role;",
   925  			"GRANT test_role TO tester@localhost;",
   926  		},
   927  		Assertions: []queries.UserPrivilegeTestAssertion{
   928  			{
   929  				User:     "tester",
   930  				Host:     "localhost",
   931  				Query:    "SELECT * FROM test;",
   932  				Expected: []sql.Row{{1}, {2}, {3}},
   933  			},
   934  			{
   935  				User:     "root",
   936  				Host:     "localhost",
   937  				Query:    "SELECT * FROM mysql.role_edges;",
   938  				Expected: []sql.Row{{"%", "test_role", "localhost", "tester", "N"}},
   939  			},
   940  			{
   941  				User:     "root",
   942  				Host:     "localhost",
   943  				Query:    "REVOKE test_role FROM tester@localhost;",
   944  				Expected: []sql.Row{{types.NewOkResult(0)}},
   945  			},
   946  			{
   947  				User:        "tester",
   948  				Host:        "localhost",
   949  				Query:       "SELECT * FROM test;",
   950  				ExpectedErr: sql.ErrDatabaseAccessDeniedForUser,
   951  			},
   952  			{
   953  				User:     "root",
   954  				Host:     "localhost",
   955  				Query:    "SELECT COUNT(*) FROM mysql.role_edges;",
   956  				Expected: []sql.Row{{0}},
   957  			},
   958  			{
   959  				User:     "root",
   960  				Host:     "localhost",
   961  				Query:    "SELECT COUNT(*) FROM mysql.user WHERE User = 'test_role';",
   962  				Expected: []sql.Row{{1}},
   963  			},
   964  			{
   965  				User:     "root",
   966  				Host:     "localhost",
   967  				Query:    "SELECT COUNT(*) FROM mysql.user WHERE User = 'tester';",
   968  				Expected: []sql.Row{{1}},
   969  			},
   970  		},
   971  	},
   972  }
   973  
   974  func TestDoltOnlyRevisionDatabasePrivileges(t *testing.T) {
   975  	for _, script := range DoltOnlyRevisionDbPrivilegeTests {
   976  		harness := newDoltHarness(t)
   977  		harness.Setup(setup.MydbData, setup.MytableData)
   978  		t.Run(script.Name, func(t *testing.T) {
   979  			engine := mustNewEngine(t, harness)
   980  			defer engine.Close()
   981  
   982  			ctx := enginetest.NewContext(harness)
   983  			ctx.NewCtxWithClient(sql.Client{
   984  				User:    "root",
   985  				Address: "localhost",
   986  			})
   987  			engine.EngineAnalyzer().Catalog.MySQLDb.AddRootAccount()
   988  			engine.EngineAnalyzer().Catalog.MySQLDb.SetPersister(&mysql_db.NoopPersister{})
   989  
   990  			for _, statement := range script.SetUpScript {
   991  				enginetest.RunQueryWithContext(t, engine, harness, ctx, statement)
   992  			}
   993  
   994  			for _, assertion := range script.Assertions {
   995  				user := assertion.User
   996  				host := assertion.Host
   997  				if user == "" {
   998  					user = "root"
   999  				}
  1000  				if host == "" {
  1001  					host = "localhost"
  1002  				}
  1003  				ctx := enginetest.NewContextWithClient(harness, sql.Client{
  1004  					User:    user,
  1005  					Address: host,
  1006  				})
  1007  				ctx.SetCurrentDatabase("mydb/b1")
  1008  
  1009  				if assertion.ExpectedErr != nil {
  1010  					t.Run(assertion.Query, func(t *testing.T) {
  1011  						enginetest.AssertErrWithCtx(t, engine, harness, ctx, assertion.Query, assertion.ExpectedErr)
  1012  					})
  1013  				} else if assertion.ExpectedErrStr != "" {
  1014  					t.Run(assertion.Query, func(t *testing.T) {
  1015  						enginetest.AssertErrWithCtx(t, engine, harness, ctx, assertion.Query, nil, assertion.ExpectedErrStr)
  1016  					})
  1017  				} else {
  1018  					t.Run(assertion.Query, func(t *testing.T) {
  1019  						enginetest.TestQueryWithContext(t, ctx, engine, harness, assertion.Query, assertion.Expected, nil, nil)
  1020  					})
  1021  				}
  1022  			}
  1023  		})
  1024  	}
  1025  }