1623 lines
62 KiB
Go
1623 lines
62 KiB
Go
// Copyright 2024 Dolthub, Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package _go
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/dolthub/go-mysql-server/sql"
|
|
|
|
"github.com/dolthub/doltgresql/server/functions"
|
|
)
|
|
|
|
const (
|
|
authTestSuperUser = "auth_test_super"
|
|
authTestSuperPass = "auth_test_spass"
|
|
authTestBasicUser = "auth_test_basic"
|
|
authTestBasicPass = "auth_test_bpass"
|
|
)
|
|
|
|
var (
|
|
authTestCreateSuperUser = fmt.Sprintf("create user if not exists '%s' with superuser password '%s';", authTestSuperUser, authTestSuperPass)
|
|
authTestCreateBasicUser = fmt.Sprintf("create user if not exists '%s' with password '%s'", authTestBasicUser, authTestBasicPass)
|
|
)
|
|
|
|
func TestAuthTests(t *testing.T) {
|
|
RunScripts(t, []ScriptTest{
|
|
{
|
|
Name: `Simple CREATE USER and DROP USER`,
|
|
Assertions: []ScriptTestAssertion{
|
|
{
|
|
Query: `SELECT 1;`,
|
|
Username: `user1`,
|
|
Password: `hello`,
|
|
ExpectedErr: `authentication failed`,
|
|
},
|
|
{
|
|
Query: `CREATE USER user1 PASSWORD 'hello';`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: `SELECT 2;`,
|
|
Username: `user1`,
|
|
Password: `hello`,
|
|
Expected: []sql.Row{{2}},
|
|
},
|
|
{
|
|
Query: `DROP USER user1;`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: `SELECT 3;`,
|
|
Username: `user1`,
|
|
Password: `hello`,
|
|
ExpectedErr: `authentication failed`,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: `ALTER PASSWORD`,
|
|
Assertions: []ScriptTestAssertion{
|
|
{
|
|
Query: `CREATE USER user1 PASSWORD 'something';`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: `SELECT 1;`,
|
|
Username: `user1`,
|
|
Password: `something`,
|
|
Expected: []sql.Row{{1}},
|
|
},
|
|
{
|
|
Query: `ALTER USER user1 PASSWORD 'another_thing';`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: `SELECT 2;`,
|
|
Username: `user1`,
|
|
Password: `something`,
|
|
ExpectedErr: `authentication failed`,
|
|
},
|
|
{
|
|
Query: `SELECT 3;`,
|
|
Username: `user1`,
|
|
Password: `another_thing`,
|
|
Expected: []sql.Row{{3}},
|
|
},
|
|
{ // No password will work, the user is effectively unable to be accessed with password-based auth
|
|
Query: `ALTER USER user1 WITH PASSWORD NULL;`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: `SELECT 4;`,
|
|
Username: `user1`,
|
|
Password: `something`,
|
|
ExpectedErr: `authentication failed`,
|
|
},
|
|
{
|
|
Query: `SELECT 5;`,
|
|
Username: `user1`,
|
|
Password: `another_thing`,
|
|
ExpectedErr: `authentication failed`,
|
|
},
|
|
{
|
|
Query: `SELECT 6;`,
|
|
Username: `user1`,
|
|
Password: ``, // Even the empty password won't work
|
|
ExpectedErr: `authentication failed`,
|
|
},
|
|
{
|
|
Query: `ALTER USER user1 PASSWORD 'different484';`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: `SELECT 7;`,
|
|
Username: `user1`,
|
|
Password: `different484`,
|
|
Expected: []sql.Row{{7}},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: `ALTER LOGIN`,
|
|
Assertions: []ScriptTestAssertion{
|
|
{ // By default, roles cannot be logged into
|
|
Query: `CREATE ROLE user1 PASSWORD 'pass1';`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{ // Users can be logged into by default, this is the only difference between roles and users
|
|
Query: `CREATE USER user2 PASSWORD 'pass2';`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{ // A role with LOGIN defined is exactly equivalent to a default user
|
|
Query: `CREATE ROLE user3 PASSWORD 'pass3' LOGIN;`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{ // A user with NOLOGIN defined is exactly equivalent to a default role
|
|
Query: `CREATE USER user4 PASSWORD 'pass4' NOLOGIN;`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: `SELECT 1;`,
|
|
Username: `user1`,
|
|
Password: `pass1`,
|
|
ExpectedErr: `authentication failed`,
|
|
},
|
|
{
|
|
Query: `SELECT 2;`,
|
|
Username: `user2`,
|
|
Password: `pass2`,
|
|
Expected: []sql.Row{{2}},
|
|
},
|
|
{
|
|
Query: `SELECT 3;`,
|
|
Username: `user3`,
|
|
Password: `pass3`,
|
|
Expected: []sql.Row{{3}},
|
|
},
|
|
{
|
|
Query: `SELECT 4;`,
|
|
Username: `user4`,
|
|
Password: `pass4`,
|
|
ExpectedErr: `authentication failed`,
|
|
},
|
|
{ // We'll flip LOGIN/NOLOGIN statuses
|
|
Query: `ALTER USER user1 WITH LOGIN;`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: `ALTER USER user2 WITH NOLOGIN;`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: `SELECT 5;`,
|
|
Username: `user1`,
|
|
Password: `pass1`,
|
|
Expected: []sql.Row{{5}},
|
|
},
|
|
{
|
|
Query: `SELECT 6;`,
|
|
Username: `user2`,
|
|
Password: `pass2`,
|
|
ExpectedErr: `authentication failed`,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: `CREATE USER IF NOT EXISTS`,
|
|
Assertions: []ScriptTestAssertion{
|
|
{
|
|
Query: `SELECT 1;`,
|
|
Username: `user1`,
|
|
Password: `hello`,
|
|
ExpectedErr: `authentication failed`,
|
|
},
|
|
{
|
|
Query: `CREATE USER user1 PASSWORD 'hello1';`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: `CREATE USER user1 PASSWORD 'hello2';`,
|
|
ExpectedErr: `already exists`,
|
|
},
|
|
{
|
|
Query: `CREATE USER IF NOT EXISTS user1 PASSWORD 'hello3';`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: `SELECT 2;`,
|
|
Username: `user1`,
|
|
Password: `hello1`,
|
|
Expected: []sql.Row{{2}},
|
|
},
|
|
{
|
|
Query: `CREATE ROLE IF NOT EXISTS user2 PASSWORD 'hi1' LOGIN;`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: `CREATE ROLE user2 PASSWORD 'hi2' LOGIN;`,
|
|
ExpectedErr: `already exists`,
|
|
},
|
|
{
|
|
Query: `CREATE ROLE IF NOT EXISTS user2 PASSWORD 'hi3' LOGIN;`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: `SELECT 3;`,
|
|
Username: `user2`,
|
|
Password: `hi1`,
|
|
Expected: []sql.Row{{3}},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: `DROP USER IF EXISTS`,
|
|
Assertions: []ScriptTestAssertion{
|
|
{
|
|
Query: `CREATE USER user1 PASSWORD 'hello1';`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: `CREATE USER user2 PASSWORD 'hello2';`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: `SELECT 1;`,
|
|
Username: `user1`,
|
|
Password: `hello1`,
|
|
Expected: []sql.Row{{1}},
|
|
},
|
|
{
|
|
Query: `SELECT 2;`,
|
|
Username: `user2`,
|
|
Password: `hello2`,
|
|
Expected: []sql.Row{{2}},
|
|
},
|
|
{
|
|
Query: `DROP USER user1;`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: `DROP USER user1;`,
|
|
ExpectedErr: `does not exist`,
|
|
},
|
|
{
|
|
Query: `DROP USER IF EXISTS user1;`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: `SELECT 3;`,
|
|
Username: `user1`,
|
|
Password: `hello1`,
|
|
ExpectedErr: `authentication failed`,
|
|
},
|
|
{
|
|
Query: `DROP ROLE IF EXISTS user2;`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: `DROP ROLE user2;`,
|
|
ExpectedErr: `does not exist`,
|
|
},
|
|
{
|
|
Query: `DROP ROLE IF EXISTS user2;`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: `SELECT 4;`,
|
|
Username: `user2`,
|
|
Password: `hello2`,
|
|
ExpectedErr: `authentication failed`,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: `DROP USER with multiple users`,
|
|
Assertions: []ScriptTestAssertion{
|
|
{
|
|
Query: `CREATE USER user1 PASSWORD 'hello1';`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: `CREATE USER user2 PASSWORD 'hello2';`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: `CREATE USER user3 PASSWORD 'hello3';`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: `SELECT 1;`,
|
|
Username: `user1`,
|
|
Password: `hello1`,
|
|
Expected: []sql.Row{{1}},
|
|
},
|
|
{
|
|
Query: `SELECT 2;`,
|
|
Username: `user2`,
|
|
Password: `hello2`,
|
|
Expected: []sql.Row{{2}},
|
|
},
|
|
{
|
|
Query: `SELECT 3;`,
|
|
Username: `user3`,
|
|
Password: `hello3`,
|
|
Expected: []sql.Row{{3}},
|
|
},
|
|
{
|
|
Query: `DROP USER user1, user3;`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: `SELECT 4;`,
|
|
Username: `user1`,
|
|
Password: `hello1`,
|
|
ExpectedErr: `authentication failed`,
|
|
},
|
|
{
|
|
Query: `SELECT 5;`,
|
|
Username: `user2`,
|
|
Password: `hello2`,
|
|
Expected: []sql.Row{{5}},
|
|
},
|
|
{
|
|
Query: `SELECT 6;`,
|
|
Username: `user3`,
|
|
Password: `hello3`,
|
|
ExpectedErr: `authentication failed`,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: `GRANT/REVOKE SELECT Privilege`,
|
|
SetUpScript: []string{
|
|
`CREATE USER user1 PASSWORD 'a';`,
|
|
`CREATE USER user2 PASSWORD 'b';`,
|
|
`GRANT ALL PRIVILEGES ON SCHEMA public TO user1;`,
|
|
`GRANT ALL PRIVILEGES ON SCHEMA public TO user2;`,
|
|
`GRANT ALL PRIVILEGES ON test TO user1 WITH GRANT OPTION;`,
|
|
},
|
|
Assertions: []ScriptTestAssertion{
|
|
{
|
|
Query: `CREATE TABLE test (pk INT4 PRIMARY KEY);`,
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: `INSERT INTO test VALUES (1), (5), (6);`,
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: `SELECT * FROM test ORDER BY pk`,
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
Expected: []sql.Row{{1}, {5}, {6}},
|
|
},
|
|
{
|
|
Query: `SELECT * FROM test ORDER BY pk`,
|
|
Username: `user2`,
|
|
Password: `b`,
|
|
ExpectedErr: `denied`,
|
|
},
|
|
{
|
|
Query: `GRANT SELECT ON test TO user2;`,
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: `SELECT * FROM test ORDER BY pk`,
|
|
Username: `user2`,
|
|
Password: `b`,
|
|
Expected: []sql.Row{{1}, {5}, {6}},
|
|
},
|
|
{
|
|
Query: `REVOKE SELECT ON test FROM user2;`,
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: `SELECT * FROM test ORDER BY pk`,
|
|
Username: `user2`,
|
|
Password: `b`,
|
|
ExpectedErr: `denied`,
|
|
},
|
|
{
|
|
Query: `GRANT SELECT ON test TO PUBLIC;`,
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: `SELECT * FROM test ORDER BY pk`,
|
|
Username: `user2`,
|
|
Password: `b`,
|
|
Expected: []sql.Row{{1}, {5}, {6}},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: `INSERT, UPDATE, DELETE Privileges`,
|
|
SetUpScript: []string{
|
|
`CREATE TABLE test (pk INT4 PRIMARY KEY);`,
|
|
`INSERT INTO test VALUES (1), (6), (7);`,
|
|
`CREATE USER user1 PASSWORD 'a';`,
|
|
},
|
|
Assertions: []ScriptTestAssertion{
|
|
{
|
|
Query: `SELECT * FROM test ORDER BY pk;`,
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
ExpectedErr: `denied`,
|
|
},
|
|
{
|
|
Query: `WITH cte AS (SELECT * FROM test ORDER BY pk) SELECT * FROM cte;`,
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
ExpectedErr: `denied`,
|
|
},
|
|
{
|
|
Query: `INSERT INTO test VALUES (10);`,
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
ExpectedErr: `denied`,
|
|
},
|
|
{
|
|
Query: `UPDATE test SET pk=pk+20;`,
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
ExpectedErr: `denied`,
|
|
},
|
|
{
|
|
Query: `DELETE FROM test WHERE pk > 3;`,
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
ExpectedErr: `denied`,
|
|
},
|
|
{
|
|
Query: `GRANT SELECT, INSERT, UPDATE, DELETE ON test TO user1;`,
|
|
Username: `postgres`,
|
|
Password: `password`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: `SELECT * FROM test ORDER BY pk;`,
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
Expected: []sql.Row{{1}, {6}, {7}},
|
|
},
|
|
{
|
|
Skip: true, // CTEs are seen as different tables
|
|
Query: `WITH cte AS (SELECT * FROM test ORDER BY pk) SELECT * FROM cte;`,
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
Expected: []sql.Row{{1}, {6}, {7}},
|
|
},
|
|
{
|
|
Query: `INSERT INTO test VALUES (10);`,
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: `UPDATE test SET pk=pk+20;`,
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: `DELETE FROM test WHERE pk = 21;`,
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: `SELECT * FROM test ORDER BY pk;`,
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
Expected: []sql.Row{{26}, {27}, {30}},
|
|
},
|
|
{
|
|
Query: `REVOKE SELECT, INSERT, UPDATE, DELETE ON test FROM user1;`,
|
|
Username: `postgres`,
|
|
Password: `password`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: `SELECT * FROM test ORDER BY pk;`,
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
ExpectedErr: `denied`,
|
|
},
|
|
{
|
|
Query: `INSERT INTO test VALUES (100);`,
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
ExpectedErr: `denied`,
|
|
},
|
|
{
|
|
Query: `UPDATE test SET pk=pk+200;`,
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
ExpectedErr: `denied`,
|
|
},
|
|
{
|
|
Query: `DELETE FROM test WHERE pk > 3;`,
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
ExpectedErr: `denied`,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: `CREATE privilege ON SEQUENCE and ROUTINE`,
|
|
SetUpScript: []string{
|
|
authTestCreateSuperUser,
|
|
`CREATE USER user1 PASSWORD 'a';`,
|
|
`CREATE USER user2 PASSWORD 'b';`,
|
|
},
|
|
Assertions: []ScriptTestAssertion{
|
|
{
|
|
Query: "CREATE FUNCTION testfunc3() RETURNS int AS $$ BEGIN RETURN 3; END; $$ LANGUAGE plpgsql",
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
ExpectedErr: `denied`,
|
|
},
|
|
{
|
|
Query: `CREATE PROCEDURE interpreted_example_3(input TEXT) AS $$ BEGIN INSERT INTO test VALUES ('3' || input); END; $$ LANGUAGE plpgsql;`,
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
ExpectedErr: `denied`,
|
|
},
|
|
{
|
|
Query: "CREATE SEQUENCE genre_id_seq_by_3 AS integer START WITH 1 INCREMENT BY 2 NO MINVALUE NO MAXVALUE CACHE 1;",
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
ExpectedErr: `denied`,
|
|
},
|
|
{
|
|
Query: `GRANT CREATE ON SCHEMA public TO user1;`,
|
|
Username: authTestSuperUser,
|
|
Password: authTestSuperPass,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: "CREATE FUNCTION testfunc3() RETURNS int AS $$ BEGIN RETURN 3; END; $$ LANGUAGE plpgsql",
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: `CREATE PROCEDURE interpreted_example_3(input TEXT) AS $$ BEGIN INSERT INTO test VALUES ('3' || input); END; $$ LANGUAGE plpgsql;`,
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: "CREATE SEQUENCE genre_id_seq_by_3 AS integer START WITH 1 INCREMENT BY 2 NO MINVALUE NO MAXVALUE CACHE 1;",
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Skip: true, // user1 is owner of this sequence, so it should have all privileges to it.
|
|
Query: "SELECT nextval('genre_id_seq_by_3');",
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
Expected: []sql.Row{{1}},
|
|
},
|
|
{
|
|
Query: `REVOKE USAGE ON SEQUENCE genre_id_seq_by_3 FROM user1;`,
|
|
Username: authTestSuperUser,
|
|
Password: authTestSuperPass,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Skip: true, // user1 is owner of this sequence, so it should have all privileges to it.
|
|
// user1 is the owner of the sequence, so the revoke is ignored.
|
|
Query: "SELECT nextval('genre_id_seq_by_3');",
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
Expected: []sql.Row{{3}},
|
|
},
|
|
{
|
|
Skip: true, // not supported yet
|
|
Query: `ALTER SEQUENCE genre_id_seq_by_3 OWNER TO auth_test_user;`,
|
|
Username: authTestSuperUser,
|
|
Password: authTestSuperPass,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Skip: true, // depends on ALTER SEQUENCE ... OWNER TO
|
|
Query: "SELECT nextval('genre_id_seq_by_3');",
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
ExpectedErr: `denied`,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Skip: true,
|
|
Name: `owner of a relation has all privileges granted by default and cannot be revoked unless ownership is altered`,
|
|
SetUpScript: []string{
|
|
authTestCreateSuperUser,
|
|
`CREATE USER user1 PASSWORD 'a';`,
|
|
`CREATE USER user2 PASSWORD 'b';`,
|
|
},
|
|
Assertions: []ScriptTestAssertion{
|
|
{
|
|
Query: "CREATE TABLE mytable (pk int);",
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
ExpectedErr: `denied`,
|
|
},
|
|
{
|
|
Query: `GRANT CREATE ON SCHEMA public TO user1;`,
|
|
Username: authTestSuperUser,
|
|
Password: authTestSuperPass,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: "CREATE TABLE mytable (pk int);",
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: "SELECT * from mytable;",
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: `GRANT/REVOKE USAGE ON SCHEMA`,
|
|
SetUpScript: []string{
|
|
authTestCreateSuperUser,
|
|
`CREATE USER user1 PASSWORD 'a';`,
|
|
`CREATE SEQUENCE genre_id_seq_by_3 AS integer START WITH 1 INCREMENT BY 2 NO MINVALUE NO MAXVALUE CACHE 1;`,
|
|
},
|
|
Assertions: []ScriptTestAssertion{
|
|
{
|
|
Query: "SELECT nextval('genre_id_seq_by_3');",
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
ExpectedErr: `denied`,
|
|
},
|
|
{
|
|
Query: `GRANT USAGE ON SCHEMA public TO user1;`,
|
|
Username: authTestSuperUser,
|
|
Password: authTestSuperPass,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: "SELECT nextval('genre_id_seq_by_3');",
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
Expected: []sql.Row{{1}},
|
|
},
|
|
{
|
|
Query: `REVOKE USAGE ON SCHEMA public FROM user1;`,
|
|
Username: authTestSuperUser,
|
|
Password: authTestSuperPass,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: "SELECT nextval('genre_id_seq_by_3');",
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
ExpectedErr: `denied`,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: `privileges ON FUNCTION`,
|
|
SetUpScript: []string{
|
|
authTestCreateSuperUser,
|
|
`CREATE USER user1 PASSWORD 'a';`,
|
|
"CREATE FUNCTION testfunc1() RETURNS int AS $$ BEGIN RETURN 1; END; $$ LANGUAGE plpgsql",
|
|
"CREATE FUNCTION testfunc2() RETURNS int AS $$ BEGIN RETURN 2; END; $$ LANGUAGE plpgsql",
|
|
},
|
|
Assertions: []ScriptTestAssertion{
|
|
{
|
|
Query: "SELECT testfunc1();",
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
ExpectedErr: `denied`,
|
|
},
|
|
{
|
|
Query: `GRANT ALL ON FUNCTION public.testfunc1() TO user1;`,
|
|
Username: authTestSuperUser,
|
|
Password: authTestSuperPass,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: "SELECT testfunc1();",
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
Expected: []sql.Row{{1}},
|
|
},
|
|
{
|
|
Query: "SELECT testfunc2();",
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
ExpectedErr: `denied`,
|
|
},
|
|
{
|
|
Query: `REVOKE ALL ON FUNCTION testfunc1() FROM user1;`,
|
|
Username: authTestSuperUser,
|
|
Password: authTestSuperPass,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: "SELECT testfunc1();",
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
ExpectedErr: `denied`,
|
|
},
|
|
{
|
|
// full privileges are granted for PUBLIC on system functions by default for now.
|
|
Query: "SELECT UPPER('hello');",
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
Expected: []sql.Row{{"HELLO"}},
|
|
},
|
|
{
|
|
// check dolt system functions work
|
|
Query: "SELECT DOLT_CHECKOUT('main');",
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
Expected: []sql.Row{{"{0,\"Already on branch 'main'\"}"}},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: `privileges ON PROCEDURE`,
|
|
SetUpScript: []string{
|
|
authTestCreateSuperUser,
|
|
`CREATE USER user1 PASSWORD 'a';`,
|
|
`CREATE TABLE test (v1 TEXT);`,
|
|
`CREATE PROCEDURE public.interpreted_example_1(input TEXT) AS $$ BEGIN INSERT INTO test VALUES ('1' || input); END; $$ LANGUAGE plpgsql;`,
|
|
`CREATE PROCEDURE interpreted_example_3(input TEXT) AS $$ BEGIN INSERT INTO test VALUES ('3' || input); END; $$ LANGUAGE plpgsql;`,
|
|
`GRANT ALL PRIVILEGES ON test TO user1 WITH GRANT OPTION;`,
|
|
},
|
|
Assertions: []ScriptTestAssertion{
|
|
{
|
|
Query: "CALL interpreted_example_1('12');",
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
ExpectedErr: `denied`,
|
|
},
|
|
{
|
|
Query: `GRANT ALL ON PROCEDURE public.interpreted_example_1(input TEXT) TO user1;`,
|
|
Username: authTestSuperUser,
|
|
Password: authTestSuperPass,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: "CALL interpreted_example_1('22');",
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: "SELECT * FROM test;",
|
|
Username: authTestSuperUser,
|
|
Password: authTestSuperPass,
|
|
Expected: []sql.Row{
|
|
{"122"},
|
|
},
|
|
},
|
|
{
|
|
Query: "CALL interpreted_example_3('32');",
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
ExpectedErr: `denied`,
|
|
},
|
|
{
|
|
Query: "SELECT * FROM test;",
|
|
Username: authTestSuperUser,
|
|
Password: authTestSuperPass,
|
|
Expected: []sql.Row{
|
|
{"122"},
|
|
},
|
|
},
|
|
{
|
|
Query: `REVOKE ALL ON PROCEDURE public.interpreted_example_1(input TEXT) FROM user1;`,
|
|
Username: authTestSuperUser,
|
|
Password: authTestSuperPass,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: "CALL interpreted_example_1('42');",
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
ExpectedErr: `denied`,
|
|
},
|
|
{
|
|
Query: "SELECT * FROM test;",
|
|
Username: authTestSuperUser,
|
|
Password: authTestSuperPass,
|
|
Expected: []sql.Row{
|
|
{"122"},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: `SELECT/USAGE privileges ON SEQUENCE`,
|
|
SetUpScript: []string{
|
|
authTestCreateSuperUser,
|
|
`CREATE USER user1 PASSWORD 'a';`,
|
|
`CREATE USER user2 PASSWORD 'b';`,
|
|
`CREATE SEQUENCE genre_id_seq_by_2 AS integer START WITH 1 INCREMENT BY 2 NO MINVALUE NO MAXVALUE CACHE 1;`,
|
|
},
|
|
Assertions: []ScriptTestAssertion{
|
|
{
|
|
Query: "SELECT nextval('genre_id_seq_by_2');",
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
ExpectedErr: `denied`,
|
|
},
|
|
{
|
|
Query: `GRANT USAGE ON SEQUENCE public.genre_id_seq_by_2 TO user1;`,
|
|
Username: authTestSuperUser,
|
|
Password: authTestSuperPass,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: "SELECT nextval('genre_id_seq_by_2');",
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
Expected: []sql.Row{{1}},
|
|
},
|
|
{
|
|
Query: `GRANT SELECT ON SEQUENCE public.genre_id_seq_by_2 TO user2;`,
|
|
Username: authTestSuperUser,
|
|
Password: authTestSuperPass,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: "SELECT nextval('genre_id_seq_by_2');",
|
|
Username: `user2`,
|
|
Password: `b`,
|
|
ExpectedErr: `denied`,
|
|
},
|
|
{
|
|
Skip: true, // TODO: support sequence metadata flag 'is_called'
|
|
Query: "SELECT is_called FROM genre_id_seq_by_2;",
|
|
Username: `user2`,
|
|
Password: `b`,
|
|
Expected: []sql.Row{{true}},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: `user can create table with sequence that they don't have privileges for but they cannot use it'`,
|
|
SetUpScript: []string{
|
|
authTestCreateSuperUser,
|
|
`CREATE USER user1 PASSWORD 'a';`,
|
|
`CREATE SEQUENCE genre_id_seq_by_2 AS integer START WITH 1 INCREMENT BY 2 NO MINVALUE NO MAXVALUE CACHE 1;`,
|
|
},
|
|
Assertions: []ScriptTestAssertion{
|
|
{
|
|
Query: "SELECT nextval('genre_id_seq_by_2');",
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
ExpectedErr: `denied`,
|
|
},
|
|
{
|
|
Query: `GRANT CREATE ON SCHEMA public TO user1;`,
|
|
Username: authTestSuperUser,
|
|
Password: authTestSuperPass,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: "create table test_by_user1 (pk int, v1 INTEGER DEFAULT nextval('genre_id_seq_by_2'));",
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
// TODO: remove this once we support ownership privileges.
|
|
// test_by_user1 table is owned by user1, so it should have all privileges
|
|
Query: `GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO user1;`,
|
|
Username: authTestSuperUser,
|
|
Password: authTestSuperPass,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: "insert into test_by_user1(pk) values (3);",
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
ExpectedErr: `denied`,
|
|
},
|
|
{
|
|
Query: "SELECT * FROM test_by_user1;",
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: `GRANT USAGE ON SEQUENCE public.genre_id_seq_by_2 TO user1;`,
|
|
Username: authTestSuperUser,
|
|
Password: authTestSuperPass,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: "insert into test_by_user1(pk) values (3);",
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Query: "SELECT * FROM test_by_user1;",
|
|
Username: `user1`,
|
|
Password: `a`,
|
|
Expected: []sql.Row{{3, 1}},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "Branch Control: Namespace entries block",
|
|
SetUpScript: []string{
|
|
"DELETE FROM dolt_branch_control WHERE user = '%';",
|
|
"INSERT INTO dolt_branch_control VALUES ('%', '%', 'postgres', '%', 'admin');",
|
|
`CREATE USER testuser PASSWORD 'a';`,
|
|
"GRANT ALL PRIVILEGES ON SCHEMA public TO testuser;",
|
|
},
|
|
Assertions: []ScriptTestAssertion{
|
|
{ // Empty table, all branches are allowed
|
|
Username: "testuser",
|
|
Password: "a",
|
|
Query: "SELECT DOLT_BRANCH('otherbranch1');",
|
|
Expected: []sql.Row{{"{0}"}},
|
|
},
|
|
{ // Prefix "other" is now locked by postgres
|
|
Username: "postgres",
|
|
Password: "password",
|
|
Query: "INSERT INTO dolt_branch_namespace_control VALUES ('%', 'other%', 'postgres', '%');",
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Username: "testuser",
|
|
Password: "a",
|
|
Query: "SELECT DOLT_BRANCH('otherbranch2');",
|
|
ExpectedErr: "cannot create a branch named",
|
|
},
|
|
{ // Allow testuser to use the "other" prefix
|
|
Username: "postgres",
|
|
Password: "password",
|
|
Query: "INSERT INTO dolt_branch_namespace_control VALUES ('%', 'other%', 'testuser', '%');",
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Username: "testuser",
|
|
Password: "a",
|
|
Query: "SELECT DOLT_BRANCH('otherbranch2');",
|
|
Expected: []sql.Row{{"{0}"}},
|
|
},
|
|
{ // Create a longer match, which takes precedence over shorter matches
|
|
Username: "postgres",
|
|
Password: "password",
|
|
Query: "INSERT INTO dolt_branch_namespace_control VALUES ('%', 'otherbranch%', 'postgres', '%');",
|
|
Expected: []sql.Row{},
|
|
},
|
|
{ // Matches both "other%" and "otherbranch%", but "otherbranch%" wins by being the longer match
|
|
Username: "testuser",
|
|
Password: "a",
|
|
Query: "SELECT DOLT_BRANCH('otherbranch3');",
|
|
ExpectedErr: "cannot create a branch named",
|
|
},
|
|
{ // This doesn't match the longer rule, so testuser has access the namespace
|
|
Username: "testuser",
|
|
Password: "a",
|
|
Query: "SELECT DOLT_BRANCH('other3');",
|
|
Expected: []sql.Row{{"{0}"}},
|
|
},
|
|
{
|
|
Username: "postgres",
|
|
Password: "password",
|
|
Query: "INSERT INTO dolt_branch_namespace_control VALUES ('%', 'otherbranch%', 'testuser', '%');",
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Username: "testuser",
|
|
Password: "a",
|
|
Query: "SELECT DOLT_BRANCH('otherbranch3');",
|
|
Expected: []sql.Row{{"{0}"}},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "Require admin to modify tables",
|
|
SetUpScript: []string{
|
|
`DELETE FROM dolt_branch_control WHERE "user" = '%';`,
|
|
"INSERT INTO dolt_branch_control VALUES ('%', '%', 'postgres', '%', 'admin');",
|
|
`CREATE USER a PASSWORD 'a';`,
|
|
`CREATE USER b PASSWORD 'b';`,
|
|
"GRANT ALL PRIVILEGES ON SCHEMA public TO a;",
|
|
"GRANT ALL PRIVILEGES ON SCHEMA public TO b;",
|
|
"GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO a;",
|
|
"GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO b;",
|
|
"INSERT INTO dolt_branch_control VALUES ('%', 'other', 'a', '%', 'write'), ('%', 'prefix%', 'a', '%', 'admin')",
|
|
},
|
|
Assertions: []ScriptTestAssertion{
|
|
{
|
|
Username: "a",
|
|
Password: "a",
|
|
Query: `DELETE FROM dolt_branch_control WHERE "branch" = 'other';`,
|
|
ExpectedErr: `cannot delete the row`,
|
|
},
|
|
{
|
|
Username: "b",
|
|
Password: "b",
|
|
Query: `DELETE FROM dolt_branch_control WHERE "branch" = 'other';`,
|
|
ExpectedErr: `cannot delete the row`,
|
|
},
|
|
{
|
|
Username: "b",
|
|
Password: "b",
|
|
Query: `DELETE FROM dolt_branch_control WHERE "branch" = 'prefix%';`,
|
|
ExpectedErr: `cannot delete the row`,
|
|
},
|
|
{
|
|
Username: "a",
|
|
Password: "a",
|
|
Query: "INSERT INTO dolt_branch_control VALUES ('%', 'prefix1%', 'b', '%', 'write');",
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Username: "b",
|
|
Password: "b",
|
|
Query: `DELETE FROM dolt_branch_control WHERE "branch" = 'prefix1%';`,
|
|
ExpectedErr: `cannot delete the row`,
|
|
},
|
|
{ // Must have permission on the new name as well
|
|
Username: "a",
|
|
Password: "a",
|
|
Query: `UPDATE dolt_branch_control SET "branch" = 'other1' WHERE "user" = 'b' AND "branch" = 'prefix1%';`,
|
|
ExpectedErr: `cannot update the row`,
|
|
},
|
|
{
|
|
Username: "b",
|
|
Password: "b",
|
|
Query: `UPDATE dolt_branch_control SET "permissions" = 'admin' WHERE "user" = 'b' AND "branch" = 'prefix1%';`,
|
|
ExpectedErr: `cannot update the row`,
|
|
},
|
|
{
|
|
Username: "a",
|
|
Password: "a",
|
|
Query: `UPDATE dolt_branch_control SET "permissions" = 'admin' WHERE "user" = 'b' AND "branch" = 'prefix1%';`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Username: "b",
|
|
Password: "b",
|
|
Query: `DELETE FROM dolt_branch_control WHERE "branch" = 'prefix1%';`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Username: "b",
|
|
Password: "b",
|
|
Query: "INSERT INTO dolt_branch_control VALUES ('%', 'prefix1%', 'b', '%', 'admin');",
|
|
ExpectedErr: `cannot add the row`,
|
|
},
|
|
{ // Since "a" has admin on "prefix%", they can also insert into the namespace table
|
|
Username: "a",
|
|
Password: "a",
|
|
Query: "INSERT INTO dolt_branch_namespace_control VALUES ('%', 'prefix___', 'a', '%');",
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Username: "b",
|
|
Password: "b",
|
|
Query: "INSERT INTO dolt_branch_namespace_control VALUES ('%', 'prefix', 'b', '%');",
|
|
ExpectedErr: `cannot add the row`,
|
|
},
|
|
{
|
|
Username: "a",
|
|
Password: "a",
|
|
Query: `UPDATE dolt_branch_namespace_control SET "branch" = 'prefix%';`,
|
|
Expected: []sql.Row{},
|
|
},
|
|
{
|
|
Username: "a",
|
|
Password: "a",
|
|
Query: `UPDATE dolt_branch_namespace_control SET "branch" = 'other';`,
|
|
ExpectedErr: `cannot update the row`,
|
|
},
|
|
{
|
|
Username: "b",
|
|
Password: "b",
|
|
Query: `DELETE FROM dolt_branch_namespace_control WHERE "branch" = 'prefix%';`,
|
|
ExpectedErr: `cannot delete the row`,
|
|
},
|
|
{
|
|
Username: "b",
|
|
Password: "b",
|
|
Query: `UPDATE dolt_branch_namespace_control SET "branch" = 'anything';`,
|
|
ExpectedErr: `cannot update the row`,
|
|
},
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
// TestAuthDoltProcedures tests that Dolt procedure functions apply permission checks for SUPERUSERs and basic users in
|
|
// SELECT statements. We test both CALL and SELECT to avoid regressions in [node.Call], where previous Doltgres'
|
|
// versions fell back to the node runner (on CALL an error is returned to use SELECT now). Some procedures also use [os]
|
|
// package calls like [os.TempDir] which can crash [filesys.InMemFS], so we use the local file system.
|
|
//
|
|
// Each time a new Dolt procedure is introduced in a ScriptTest, it's grouped into a set of related procedures. Each set
|
|
// is separated by a new line.
|
|
func TestAuthDoltProcedures(t *testing.T) {
|
|
tempDir, err := os.MkdirTemp("", t.Name())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
t.Cleanup(func() { _ = os.RemoveAll(tempDir) })
|
|
authTestFireUrl := func(path string) string {
|
|
return "file://" + filepath.ToSlash(filepath.Join(tempDir, path))
|
|
}
|
|
RunScripts(t, []ScriptTest{
|
|
{
|
|
UseLocalFileSystem: true,
|
|
Name: "SUPERUSER authorization for CALL executing Dolt stored procedures",
|
|
SetUpScript: []string{
|
|
authTestCreateSuperUser,
|
|
"create table test_table (v int);",
|
|
"insert into test_table values (1);",
|
|
"select dolt_add('test_table');",
|
|
"select dolt_commit('-m', 'add test table');",
|
|
},
|
|
Assertions: []ScriptTestAssertion{
|
|
authTestAssertAsSuper(fmt.Sprintf("call dolt_backup('sync-url', '%s');", authTestFireUrl("bak1")), nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
authTestAssertAsSuper(fmt.Sprintf("call dolt_backup('add', 'bak1', '%s');", authTestFireUrl("bak1")), nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
authTestAssertAsSuper("call dolt_checkout('-b', 'test');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
authTestAssertAsSuper("call dolt_branch('new_branch');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
authTestAssertAsSuper("insert into test_table values (2);", []sql.Row{}, ""),
|
|
authTestAssertAsSuper("call dolt_add('.');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
authTestAssertAsSuper("call dolt_commit('-m', 'amend test table');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
authTestAssertAsSuper("call dolt_checkout('main');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
authTestAssertAsSuper("call dolt_cherry_pick('test');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
authTestAssertAsSuper("call dolt_clean('--dry-run');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
authTestAssertAsSuper(fmt.Sprintf("call dolt_clone('%s', 'cloned_bak1');", authTestFireUrl("bak1")), nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
authTestAssertAsSuper("set authtest.hash = ''", []sql.Row{}, ""),
|
|
authTestAssertAsSuper("call dolt_commit_hash_out('authtest.hash', '-am', 'add val 3 to test table')", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
authTestAssertAsSuper("call dolt_checkout('-b', 'conflict');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
authTestAssertAsSuper("update test_table set v = -1 where v = 1;", []sql.Row{}, ""),
|
|
authTestAssertAsSuper("call dolt_commit('-am', 'amend 1 to -1');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
authTestAssertAsSuper("call dolt_checkout('main');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
authTestAssertAsSuper("update test_table set v = -2 where v = 1;", []sql.Row{}, ""),
|
|
authTestAssertAsSuper("call dolt_commit('-am', 'amend 2 to -2');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
authTestAssertAsSuper("set dolt_allow_commit_conflicts to 1;", []sql.Row{}, ""),
|
|
authTestAssertAsSuper("call dolt_merge('conflict');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
authTestAssertAsSuper("call dolt_conflicts_resolve('--theirs', 'test_table');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
authTestAssertAsSuper("call dolt_count_commits('--from=main', '--to=test');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
authTestAssertAsSuper("call dolt_backup('remove', 'bak1');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
authTestAssertAsSuper(fmt.Sprintf("call dolt_remote('add', 'origin', '%s');", authTestFireUrl("bak1")), nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
authTestAssertAsSuper("call dolt_fetch('origin', 'main');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
authTestAssertAsSuper("call dolt_undrop('cloned_bak1');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
authTestAssertAsSuper("call dolt_commit('-am', 'resolve conflicts');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
authTestAssertAsSuper("call dolt_update_column_tag('test_table', 'v', '123');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
// TODO(elianddb): "procedure aggregation is not yet supported" error blocks no-parameter CALLs
|
|
authTestSkipAsSuper("call dolt_purge_dropped_databases();", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
authTestAssertAsSuper("call dolt_checkout('test');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
authTestAssertAsSuper("call dolt_rebase('-i', 'main');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
authTestAssertAsSuper("call dolt_rebase('--abort');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
authTestAssertAsSuper("create table to_rm (v int);", []sql.Row{}, ""),
|
|
authTestAssertAsSuper("call dolt_add('to_rm');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
authTestAssertAsSuper("call dolt_commit('-m', 'clean state to_rm');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
authTestAssertAsSuper("call dolt_rm('to_rm');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
authTestAssertAsSuper("call dolt_gc('--shallow');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
// TODO(elianddb): "procedure aggregation is not yet supported" error blocks no-parameter CALLs
|
|
authTestSkipAsSuper("call dolt_thread_dump();", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
authTestAssertAsSuper("call dolt_commit('-m', 'rm to_rm');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
authTestAssertAsSuper("call dolt_push('origin', 'test');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
authTestAssertAsSuper("call dolt_pull('origin', 'test');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
authTestAssertAsSuper("call dolt_reset('--soft', 'HEAD~1');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
authTestAssertAsSuper("call dolt_stash('push', 'to_rm');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
authTestAssertAsSuper("call dolt_tag('-m', 'dolt_rm procedure', 'to_rm', 'HEAD');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
authTestAssertAsSuper("call dolt_verify_constraints('--all');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
authTestAssertAsSuper("call dolt_stats_info('--short');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
// TODO(elianddb): "procedure aggregation is not yet supported" error blocks no-parameter CALLs
|
|
authTestSkipAsSuper("call dolt_stats_wait();", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
authTestSkipAsSuper("call dolt_stats_flush();", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
authTestSkipAsSuper("call dolt_stats_gc();", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
authTestSkipAsSuper("call dolt_stats_purge();", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
authTestSkipAsSuper("call dolt_stats_restart();", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
authTestSkipAsSuper("call dolt_stats_once();", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
},
|
|
},
|
|
{
|
|
UseLocalFileSystem: true,
|
|
Name: "Basic user authentication for CALL executing Dolt stored procedures",
|
|
SetUpScript: []string{
|
|
authTestCreateBasicUser,
|
|
fmt.Sprintf("alter user %s createdb;", authTestBasicUser),
|
|
authTestCreateSuperUser,
|
|
"create table test_table (v int);",
|
|
"insert into test_table values (1);",
|
|
"select dolt_add('test_table');",
|
|
"select dolt_commit('-m', 'add test table');",
|
|
},
|
|
Assertions: []ScriptTestAssertion{
|
|
authTestAssertAsBasic(fmt.Sprintf("call dolt_backup('sync-url', '%s');", authTestFireUrl("bak1")), nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
authTestAssertAsBasic(fmt.Sprintf("call dolt_backup('add', 'bak1', '%s');", authTestFireUrl("bak1")), nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
// Grant user access to test_table before checkout to avoid merge conflict in later cherry-pick.
|
|
authTestGrantBasic("schema public", "all"),
|
|
authTestGrantBasic("test_table", "select", "insert", "delete", "update"),
|
|
authTestAssertAsBasic("call dolt_checkout('-b', 'test');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
authTestAssertAsBasic("call dolt_branch('new_branch');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
authTestAssertAsBasic("insert into test_table values (2);", []sql.Row{}, ""),
|
|
authTestAssertAsBasic("call dolt_add('.');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
authTestAssertAsBasic("call dolt_commit('-m', 'amend test table');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
authTestAssertAsBasic("call dolt_checkout('main');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
authTestAssertAsBasic("call dolt_cherry_pick('test');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
authTestAssertAsBasic("call dolt_clean('--dry-run');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
authTestAssertAsBasic(fmt.Sprintf("call dolt_clone('%s', 'cloned_bak1');", authTestFireUrl("bak1")), nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
authTestAssertAsBasic("create database cloned_bak1;", []sql.Row{}, ""),
|
|
|
|
authTestAssertAsSuper("set authtest.hash = '';", []sql.Row{}, ""),
|
|
authTestAssertAsSuper("call dolt_commit_hash_out('authtest.hash', '-am', 'add val 3 to test table');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
authTestAssertAsBasic("call dolt_checkout('-b', 'conflict');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
authTestAssertAsBasic("update test_table set v = -1 where v = 1;", []sql.Row{}, ""),
|
|
authTestAssertAsBasic("call dolt_commit('-am', 'amend 1 to -1');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
authTestAssertAsBasic("call dolt_checkout('main');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
authTestAssertAsBasic("update test_table set v = -2 where v = 1;", []sql.Row{}, ""),
|
|
authTestAssertAsBasic("call dolt_commit('-am', 'amend 2 to -2');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
authTestAssertAsBasic("set dolt_allow_commit_conflicts to 1;", []sql.Row{}, ""),
|
|
authTestAssertAsBasic("call dolt_merge('conflict');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
authTestAssertAsBasic("call dolt_conflicts_resolve('--theirs', 'test_table');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
authTestAssertAsBasic("call dolt_count_commits('--from=main', '--to=test');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
authTestAssertAsBasic("call dolt_backup('remove', 'bak1');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
authTestAssertAsBasic(fmt.Sprintf("call dolt_remote('add', 'origin', '%s');", authTestFireUrl("bak1")), nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
authTestAssertAsBasic("call dolt_fetch('origin', 'main');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
authTestAssertAsBasic("call dolt_undrop('cloned_bak1');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
authTestAssertAsBasic("call dolt_commit('-am', 'resolve conflicts');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
authTestAssertAsBasic("call dolt_update_column_tag('test_table', 'v', '123');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
authTestAssertAsBasic("drop database cloned_bak1;", []sql.Row{}, ""),
|
|
// TODO(elianddb): "procedure aggregation is not yet supported" error blocks no-parameter CALLs
|
|
authTestSkipAssertAsBasic("call dolt_purge_dropped_databases();", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
authTestAssertAsBasic("call dolt_checkout('test');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
authTestAssertAsBasic("call dolt_rebase('-i', 'main');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
authTestAssertAsBasic("call dolt_rebase('--abort');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
authTestAssertAsBasic("create table to_rm (v int);", []sql.Row{}, ""),
|
|
authTestAssertAsBasic("call dolt_add('to_rm');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
authTestAssertAsBasic("call dolt_commit('-m', 'clean state to_rm');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
authTestAssertAsBasic("call dolt_rm('to_rm');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
authTestAssertAsBasic("call dolt_gc('--shallow');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
// TODO(elianddb): "procedure aggregation is not yet supported" error blocks no-parameter CALLs
|
|
authTestSkipAssertAsBasic("call dolt_thread_dump();", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
authTestAssertAsBasic("call dolt_commit('-m', 'rm to_rm');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
authTestAssertAsBasic("call dolt_push('origin', 'test');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
authTestAssertAsBasic("call dolt_pull('origin', 'test');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
authTestAssertAsBasic("call dolt_reset('--soft', 'HEAD~1');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
authTestAssertAsBasic("call dolt_stash('push', 'to_rm');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
authTestAssertAsBasic("call dolt_tag('-m', 'dolt_rm procedure', 'to_rm', 'HEAD');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
authTestAssertAsBasic("call dolt_verify_constraints('--all');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
authTestAssertAsBasic("call dolt_stats_info('--short');", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
|
|
// TODO(elianddb): "procedure aggregation is not yet supported" error blocks no-parameter CALLs
|
|
authTestSkipAssertAsBasic("call dolt_stats_wait();", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
authTestSkipAssertAsBasic("call dolt_stats_flush();", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
authTestSkipAssertAsBasic("call dolt_stats_gc();", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
authTestSkipAssertAsBasic("call dolt_stats_purge();", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
authTestSkipAssertAsBasic("call dolt_stats_restart();", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
authTestSkipAssertAsBasic("call dolt_stats_once();", nil, functions.ErrDoltProcedureSelectOnly.Error()),
|
|
},
|
|
},
|
|
{
|
|
UseLocalFileSystem: true,
|
|
Name: "SUPERUSER authorization for SELECT executing Dolt stored procedures",
|
|
SetUpScript: []string{
|
|
authTestCreateSuperUser,
|
|
"create table test_table (v int);",
|
|
"insert into test_table values (1);",
|
|
"select dolt_add('test_table');",
|
|
"select dolt_commit('-m', 'add test table');",
|
|
},
|
|
Assertions: []ScriptTestAssertion{
|
|
authTestAssertAsSuper(fmt.Sprintf("select dolt_backup('sync-url', '%s');", authTestFireUrl("bak1")), []sql.Row{{"{0}"}}, ""),
|
|
authTestAssertAsSuper(fmt.Sprintf("select dolt_backup('add', 'bak1', '%s');", authTestFireUrl("bak1")), []sql.Row{{"{0}"}}, ""),
|
|
|
|
authTestAssertAsSuper("select dolt_checkout('-b', 'test');", []sql.Row{{"{0,\"Switched to branch 'test'\"}"}}, ""),
|
|
|
|
authTestAssertAsSuper("select dolt_branch('new_branch');", []sql.Row{{"{0}"}}, ""),
|
|
|
|
authTestAssertAsSuper("insert into test_table values (2);", []sql.Row{}, ""),
|
|
authTestAssertAsSuper("select dolt_add('.');", []sql.Row{{"{0}"}}, ""),
|
|
authTestAssertAsSuper("select length(dolt_commit('-m', 'amend test table')::text) = 34;", []sql.Row{{"t"}}, ""),
|
|
|
|
authTestAssertAsSuper("select dolt_checkout('main');", []sql.Row{{"{0,\"Switched to branch 'main'\"}"}}, ""),
|
|
authTestAssertAsSuper("select length(dolt_cherry_pick('test')::text);", []sql.Row{{40}}, ""),
|
|
|
|
authTestAssertAsSuper("select dolt_clean('--dry-run');", []sql.Row{{"{0}"}}, ""),
|
|
|
|
authTestAssertAsSuper(fmt.Sprintf("select dolt_clone('%s', 'cloned_bak1');", authTestFireUrl("bak1")), []sql.Row{{"{0}"}}, ""),
|
|
|
|
authTestAssertAsSuper("set authtest.hash = '';", []sql.Row{}, ""),
|
|
// TODO(elianddb): variadic parameter support for Dolt stored procedures functions
|
|
authTestSkipAsSuper("select dolt_commit_hash_out('authtest.hash', '-am', 'add val 3 to test table');", []sql.Row{{"{0}"}}, ""),
|
|
|
|
authTestAssertAsSuper("select dolt_checkout('-b', 'conflict');", []sql.Row{{"{0,\"Switched to branch 'conflict'\"}"}}, ""),
|
|
authTestAssertAsSuper("update test_table set v = -1 where v = 1;", []sql.Row{}, ""),
|
|
authTestAssertAsSuper("select length(dolt_commit('-am', 'amend 1 to -1')::text) = 34;", []sql.Row{{"t"}}, ""),
|
|
authTestAssertAsSuper("select dolt_checkout('main');", []sql.Row{{"{0,\"Switched to branch 'main'\"}"}}, ""),
|
|
authTestAssertAsSuper("update test_table set v = -2 where v = 1;", []sql.Row{}, ""),
|
|
authTestAssertAsSuper("select length(dolt_commit('-am', 'amend 2 to -2')::text) = 34;", []sql.Row{{"t"}}, ""),
|
|
authTestAssertAsSuper("set dolt_allow_commit_conflicts to 1;", []sql.Row{}, ""),
|
|
authTestAssertAsSuper("select dolt_merge('conflict');", []sql.Row{{`{"",0,1,"conflicts found"}`}}, ""),
|
|
|
|
authTestAssertAsSuper("select dolt_conflicts_resolve('--theirs', 'test_table');", []sql.Row{{"{0}"}}, ""),
|
|
|
|
// TODO(elianddb): unsupported type uint64
|
|
authTestSkipAsSuper("select dolt_count_commits('--from=main', '--to=test');", []sql.Row{{"{0}"}}, ""),
|
|
|
|
authTestAssertAsSuper("select dolt_backup('remove', 'bak1');", []sql.Row{{"{0}"}}, ""),
|
|
authTestAssertAsSuper(fmt.Sprintf("select dolt_backup('add', 'bak2', '%s');", authTestFireUrl("bak2")), []sql.Row{{"{0}"}}, ""),
|
|
authTestAssertAsSuper("select dolt_backup('sync', 'bak2');", []sql.Row{{"{0}"}}, ""),
|
|
authTestAssertAsSuper(fmt.Sprintf("select dolt_backup('restore', '%s', 'restored_db');", authTestFireUrl("bak2")), []sql.Row{{"{0}"}}, ""),
|
|
authTestAssertAsSuper("drop database restored_db;", []sql.Row{}, ""),
|
|
authTestAssertAsSuper("select dolt_backup('remove', 'bak2');", []sql.Row{{"{0}"}}, ""),
|
|
authTestAssertAsSuper(fmt.Sprintf("select dolt_remote('add', 'origin', '%s');", authTestFireUrl("bak1")), []sql.Row{{"{0}"}}, ""),
|
|
|
|
authTestAssertAsSuper("select dolt_fetch('origin', 'main');", []sql.Row{{"{0}"}}, ""),
|
|
|
|
authTestAssertAsSuper("drop database cloned_bak1", []sql.Row{}, ""),
|
|
authTestAssertAsSuper("select dolt_undrop('cloned_bak1');", []sql.Row{{"{0}"}}, ""),
|
|
|
|
authTestAssertAsSuper("select length(dolt_commit('-am', 'resolve conflicts')::text) = 34;", []sql.Row{{"t"}}, ""),
|
|
// TODO(elianddb): table test_table does not exist (also tried with public.test_table)
|
|
authTestSkipAsSuper("select dolt_update_column_tag('test_table', 'v', '123');", []sql.Row{{"{0}"}}, ""),
|
|
|
|
authTestAssertAsSuper("drop database cloned_bak1", []sql.Row{}, ""),
|
|
authTestAssertAsSuper("select dolt_purge_dropped_databases();", []sql.Row{{"{0}"}}, ""),
|
|
|
|
authTestAssertAsSuper("select dolt_checkout('test');", []sql.Row{{"{0,\"Switched to branch 'test'\"}"}}, ""),
|
|
authTestAssertAsSuper(
|
|
"select dolt_rebase('-i', 'main');",
|
|
[]sql.Row{{"{0,\"interactive rebase started on branch dolt_rebase_test; adjust the rebase plan in the dolt_rebase table, then continue rebasing by calling dolt_rebase('--continue')\"}"}},
|
|
""),
|
|
authTestAssertAsSuper("select dolt_rebase('--abort');", []sql.Row{{"{0,\"Interactive rebase aborted\"}"}}, ""),
|
|
|
|
authTestAssertAsSuper("create table to_rm (v int);", []sql.Row{}, ""),
|
|
authTestAssertAsSuper("select dolt_add('to_rm');", []sql.Row{{"{0}"}}, ""),
|
|
authTestAssertAsSuper("select length(dolt_commit('-m', 'clean state to_rm')::text) = 34;", []sql.Row{{"t"}}, ""),
|
|
authTestAssertAsSuper("select dolt_rm('to_rm');", []sql.Row{{"{0}"}}, ""),
|
|
|
|
authTestAssertAsSuper("select dolt_gc('--shallow');", []sql.Row{{"{0}"}}, ""),
|
|
|
|
// The paths for files, memory addresses, and number of goroutines can be different per OS.
|
|
authTestAssertAsSuper("select instr(dolt_thread_dump()::text, 'goroutine') > 0;", []sql.Row{{"t"}}, ""),
|
|
|
|
authTestAssertAsSuper("select length(dolt_commit('-m', 'rm to_rm')::text) = 34;", []sql.Row{{"t"}}, ""),
|
|
authTestAssertAsSuper(
|
|
"select dolt_push('origin', 'test');",
|
|
[]sql.Row{{fmt.Sprintf("{0,\"To %s\n * [new branch] test -> test\"}", authTestFireUrl("bak1"))}},
|
|
""),
|
|
authTestAssertAsSuper("select dolt_pull('origin', 'test');", []sql.Row{{"{0,0,\"Everything up-to-date\"}"}}, ""),
|
|
|
|
authTestAssertAsSuper("select dolt_reset('--soft', 'HEAD~1');", []sql.Row{{"{0}"}}, ""),
|
|
// TODO(elianddb): unsupported type int
|
|
authTestSkipAsSuper("select dolt_stash('push', 'to_rm');", []sql.Row{{"{0}"}}, ""),
|
|
|
|
authTestAssertAsSuper("select dolt_tag('-m', 'dolt_rm procedure', 'to_rm', 'HEAD');", []sql.Row{{"{0}"}}, ""),
|
|
authTestAssertAsSuper("select dolt_verify_constraints('--all');", []sql.Row{{"{0}"}}, ""),
|
|
|
|
// TODO(elianddb): provider does not implement ExtendedStatsProvider
|
|
authTestSkipAsSuper("select dolt_stats_info('--short');", []sql.Row{{"{0}"}}, ""),
|
|
authTestSkipAsSuper("select dolt_stats_wait();", []sql.Row{{"{0}"}}, ""),
|
|
authTestSkipAsSuper("select dolt_stats_flush();", []sql.Row{{"{0}"}}, ""),
|
|
authTestSkipAsSuper("select dolt_stats_gc();", []sql.Row{{"{0}"}}, ""),
|
|
authTestSkipAsSuper("select dolt_stats_purge();", []sql.Row{{"{0}"}}, ""),
|
|
authTestSkipAsSuper("select dolt_stats_restart();", []sql.Row{{"{0}"}}, ""),
|
|
authTestSkipAsSuper("select dolt_stats_once();", []sql.Row{{"{0}"}}, ""),
|
|
},
|
|
},
|
|
{
|
|
UseLocalFileSystem: true,
|
|
Name: "Basic user authorization for SELECT executing Dolt stored procedures",
|
|
SetUpScript: []string{
|
|
authTestCreateBasicUser,
|
|
fmt.Sprintf("alter user %s createdb;", authTestBasicUser),
|
|
authTestCreateSuperUser,
|
|
"create table test_table (v int);",
|
|
"insert into test_table values (1);",
|
|
"select dolt_add('test_table');",
|
|
"select dolt_commit('-m', 'add test table');",
|
|
},
|
|
Assertions: []ScriptTestAssertion{
|
|
authTestAssertAsBasic(fmt.Sprintf("select dolt_backup('sync-url', '%s');", authTestFireUrl("bak1")), nil, functions.ErrDoltProcedurePermissionDenied.Error()),
|
|
authTestAssertAsBasic(fmt.Sprintf("select dolt_backup('add', 'bak1', '%s');", authTestFireUrl("bak1")), nil, functions.ErrDoltProcedurePermissionDenied.Error()),
|
|
|
|
// Grant user access to test_table before checkout to avoid merge conflict in later cherry-pick.
|
|
authTestGrantBasic("schema public", "all"),
|
|
authTestGrantBasic("test_table", "select", "insert", "delete", "update"),
|
|
authTestAssertAsBasic("select dolt_checkout('-b', 'test');", []sql.Row{{"{0,\"Switched to branch 'test'\"}"}}, ""),
|
|
|
|
authTestAssertAsBasic("select dolt_branch('new_branch');", []sql.Row{{"{0}"}}, ""),
|
|
|
|
authTestAssertAsBasic("insert into test_table values (2);", []sql.Row{}, ""),
|
|
authTestAssertAsBasic("select dolt_add('.');", []sql.Row{{"{0}"}}, ""),
|
|
authTestAssertAsBasic("select length(dolt_commit('-m', 'amend test table')::text) = 34;", []sql.Row{{"t"}}, ""),
|
|
|
|
authTestAssertAsBasic("select dolt_checkout('main');", []sql.Row{{"{0,\"Switched to branch 'main'\"}"}}, ""),
|
|
authTestAssertAsBasic("select length(dolt_cherry_pick('test')::text);", []sql.Row{{40}}, ""),
|
|
|
|
authTestAssertAsBasic("select dolt_clean('--dry-run');", []sql.Row{{"{0}"}}, ""),
|
|
|
|
authTestAssertAsBasic(fmt.Sprintf("select dolt_clone('%s', 'cloned_bak1');", authTestFireUrl("bak1")), nil, functions.ErrDoltProcedurePermissionDenied.Error()),
|
|
authTestAssertAsBasic("create database cloned_bak1;", []sql.Row{}, ""),
|
|
|
|
authTestAssertAsBasic("set authtest.hash = '';", []sql.Row{}, ""),
|
|
// TODO(elianddb): variadic parameter support for Dolt stored procedures
|
|
authTestSkipAssertAsBasic("select dolt_commit_hash_out('authtest.hash', '-am', 'add val 3 to test table');", []sql.Row{{"{0}"}}, ""),
|
|
|
|
authTestAssertAsBasic("select dolt_checkout('-b', 'conflict');", []sql.Row{{"{0,\"Switched to branch 'conflict'\"}"}}, ""),
|
|
authTestAssertAsBasic("update test_table set v = -1 where v = 1;", []sql.Row{}, ""),
|
|
authTestAssertAsBasic("select length(dolt_commit('-am', 'amend 1 to -1')::text) = 34;", []sql.Row{{"t"}}, ""),
|
|
authTestAssertAsBasic("select dolt_checkout('main');", []sql.Row{{"{0,\"Switched to branch 'main'\"}"}}, ""),
|
|
authTestAssertAsBasic("update test_table set v = -2 where v = 1;", []sql.Row{}, ""),
|
|
authTestAssertAsBasic("select length(dolt_commit('-am', 'amend 2 to -2')::text) = 34;", []sql.Row{{"t"}}, ""),
|
|
authTestAssertAsBasic("set dolt_allow_commit_conflicts to 1;", []sql.Row{}, ""),
|
|
authTestAssertAsBasic("select dolt_merge('conflict');", []sql.Row{{`{"",0,1,"conflicts found"}`}}, ""),
|
|
|
|
authTestAssertAsBasic("select dolt_conflicts_resolve('--theirs', 'test_table');", []sql.Row{{"{0}"}}, ""),
|
|
|
|
// TODO(elianddb): unsupported type uint64
|
|
authTestSkipAssertAsBasic("select dolt_count_commits('--from=main', '--to=test');", []sql.Row{{"{0}"}}, ""),
|
|
|
|
authTestAssertAsBasic("select dolt_backup('remove', 'bak1');", nil, functions.ErrDoltProcedurePermissionDenied.Error()),
|
|
authTestAssertAsBasic("select dolt_backup('sync', 'bak1');", nil, functions.ErrDoltProcedurePermissionDenied.Error()),
|
|
authTestAssertAsBasic(fmt.Sprintf("select dolt_backup('restore', '%s', 'restored_db');", authTestFireUrl("bak1")), nil, functions.ErrDoltProcedurePermissionDenied.Error()),
|
|
authTestAssertAsBasic(fmt.Sprintf("select dolt_remote('add', 'origin', '%s');", authTestFireUrl("bak1")), nil, functions.ErrDoltProcedurePermissionDenied.Error()),
|
|
|
|
authTestAssertAsBasic("select dolt_fetch('origin', 'main');", nil, functions.ErrDoltProcedurePermissionDenied.Error()),
|
|
|
|
authTestAssertAsBasic("drop database cloned_bak1", []sql.Row{}, ""),
|
|
authTestAssertAsBasic("select dolt_undrop('cloned_bak1');", nil, functions.ErrDoltProcedurePermissionDenied.Error()),
|
|
|
|
authTestAssertAsBasic("select length(dolt_commit('-am', 'resolve conflicts')::text) = 34;", []sql.Row{{"t"}}, ""),
|
|
// TODO(elianddb): table test_table does not exist (also tried with public.test_table)
|
|
authTestSkipAssertAsBasic("select dolt_update_column_tag('test_table', 'v', '123');", []sql.Row{{"{0}"}}, ""),
|
|
|
|
authTestAssertAsBasic("select dolt_purge_dropped_databases();", nil, functions.ErrDoltProcedurePermissionDenied.Error()),
|
|
|
|
authTestAssertAsBasic("select dolt_checkout('test');", []sql.Row{{"{0,\"Switched to branch 'test'\"}"}}, ""),
|
|
authTestAssertAsBasic(
|
|
"select dolt_rebase('-i', 'main');",
|
|
[]sql.Row{{"{0,\"interactive rebase started on branch dolt_rebase_test; adjust the rebase plan in the dolt_rebase table, then continue rebasing by calling dolt_rebase('--continue')\"}"}},
|
|
""),
|
|
authTestAssertAsBasic("select dolt_rebase('--abort');", []sql.Row{{"{0,\"Interactive rebase aborted\"}"}}, ""),
|
|
|
|
authTestAssertAsBasic("create table to_rm (v int);", []sql.Row{}, ""),
|
|
authTestAssertAsBasic("select dolt_add('to_rm');", []sql.Row{{"{0}"}}, ""),
|
|
authTestAssertAsBasic("select length(dolt_commit('-m', 'clean state to_rm')::text) = 34;", []sql.Row{{"t"}}, ""),
|
|
authTestAssertAsBasic("select dolt_rm('to_rm');", []sql.Row{{"{0}"}}, ""),
|
|
|
|
authTestAssertAsBasic("select dolt_gc('--shallow');", nil, functions.ErrDoltProcedurePermissionDenied.Error()),
|
|
|
|
authTestAssertAsBasic("select dolt_thread_dump();", nil, functions.ErrDoltProcedurePermissionDenied.Error()),
|
|
|
|
authTestAssertAsBasic("select length(dolt_commit('-m', 'rm to_rm')::text) = 34;", []sql.Row{{"t"}}, ""),
|
|
authTestAssertAsBasic("select dolt_push('origin', 'test');", nil, functions.ErrDoltProcedurePermissionDenied.Error()),
|
|
authTestAssertAsBasic("select dolt_pull('origin', 'test');", nil, functions.ErrDoltProcedurePermissionDenied.Error()),
|
|
|
|
authTestAssertAsBasic("select dolt_reset('--soft', 'HEAD~1');", []sql.Row{{"{0}"}}, ""),
|
|
// TODO(elianddb): unsupported type int
|
|
authTestSkipAssertAsBasic("select dolt_stash('push', 'to_rm');", []sql.Row{{"{0}"}}, ""),
|
|
|
|
authTestAssertAsBasic("select dolt_tag('-m', 'dolt_rm procedure', 'to_rm', 'HEAD');", []sql.Row{{"{0}"}}, ""),
|
|
authTestAssertAsBasic("select dolt_verify_constraints('--all');", []sql.Row{{"{0}"}}, ""),
|
|
|
|
// TODO(elianddb): provider does not implement ExtendedStatsProvider
|
|
authTestSkipAssertAsBasic("select dolt_stats_info('--short');", []sql.Row{{"{0}"}}, ""),
|
|
authTestSkipAssertAsBasic("select dolt_stats_wait();", []sql.Row{{"{0}"}}, ""),
|
|
authTestSkipAssertAsBasic("select dolt_stats_flush();", []sql.Row{{"{0}"}}, ""),
|
|
authTestSkipAssertAsBasic("select dolt_stats_gc();", []sql.Row{{"{0}"}}, ""),
|
|
authTestSkipAssertAsBasic("select dolt_stats_purge();", []sql.Row{{"{0}"}}, ""),
|
|
authTestSkipAssertAsBasic("select dolt_stats_restart();", []sql.Row{{"{0}"}}, ""),
|
|
authTestSkipAssertAsBasic("select dolt_stats_once();", []sql.Row{{"{0}"}}, ""),
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
// authTestAssertAsSuper returns a ScriptTestAssertion for the given |query|, |expectedResultSet|, and/or |expectedErr| using
|
|
// authTestSuperUser.
|
|
func authTestAssertAsSuper(query string, expectedResultSet []sql.Row, expectedErr string) ScriptTestAssertion {
|
|
return ScriptTestAssertion{
|
|
Username: authTestSuperUser,
|
|
Password: authTestSuperPass,
|
|
Query: query,
|
|
Expected: expectedResultSet,
|
|
ExpectedErr: expectedErr,
|
|
}
|
|
}
|
|
|
|
// authTestSkipAsSuper skips the returned assertion from authTestAssertAsSuper.
|
|
func authTestSkipAsSuper(query string, expectedResultSet []sql.Row, expectedErr string) ScriptTestAssertion {
|
|
assertion := authTestAssertAsSuper(query, expectedResultSet, expectedErr)
|
|
assertion.Skip = true
|
|
return assertion
|
|
}
|
|
|
|
// authTestAssertAsBasic returns a ScriptTestAssertion for the given |query|, |expectedResultSet|, and/or |expectedErr| using
|
|
// authTestBasicUser.
|
|
func authTestAssertAsBasic(query string, expected []sql.Row, expectedErr string) ScriptTestAssertion {
|
|
return ScriptTestAssertion{
|
|
Username: authTestBasicUser,
|
|
Password: authTestBasicPass,
|
|
Query: query,
|
|
Expected: expected,
|
|
ExpectedErr: expectedErr,
|
|
}
|
|
}
|
|
|
|
// authTestSkipAssertAsBasic skips the returned assertion from authTestAssertAsBasic.
|
|
func authTestSkipAssertAsBasic(query string, expected []sql.Row, expectedErr string) ScriptTestAssertion {
|
|
assertion := authTestAssertAsBasic(query, expected, expectedErr)
|
|
assertion.Skip = true
|
|
return assertion
|
|
}
|
|
|
|
// authTestGrantBasic grants |privileges| to authTestBasicUser on given |object| (include the object type in |object| if
|
|
// applicable).
|
|
func authTestGrantBasic(object string, privileges ...string) ScriptTestAssertion {
|
|
return ScriptTestAssertion{
|
|
Username: "postgres",
|
|
Password: "password",
|
|
Query: fmt.Sprintf("GRANT %s ON %s TO %s", strings.Join(privileges, ","), object, authTestBasicUser),
|
|
Expected: []sql.Row{},
|
|
}
|
|
}
|