dolt
Here, we will go through a fix for this bug where Dolt wasn't respecting a config flag to demonstrate how to make a change to Dolt.

Setup

Follow these setup instructions.

Identifying the Bug

Dolt has the ability to host a SQL server and take in user queries to create, modify, and drop tables. The server allows users to provide a config file through the --config option. A customer claimed that the read_only flag in their config file was not being respected when using the dolt server; this means that the server was allowing users to run queries that modified data on the server.
First off, let's try to reproduce the issue. Create a dolt database:
1
$ cd ~/dolt_workspace
2
$ mkdir test_db
3
$ cd test_db
4
$ dolt init
Copied!
Create a config file named config.yml and put this in it:
1
log_level: debug
2
user:
3
name: dolt
4
listener:
5
host: "0.0.0.0"
6
port: $PORT
7
behavior:
8
read_only: true
Copied!
We have a file called pytest.py located in ~/dolt_workspace/dolt/integration-tests/bats/helper, which contains many useful helper methods for testing dolt sql-server. I wrote a quick Python script using methods from pytest.py to send queries and look at the results manually.
1
from pytest import *
2
# Create a new connection
3
dc = DoltConnection(port=3000, database="test_db", user="dolt", auto_commit=1)
4
dc.connect()
5
try:
6
actual_rows, num_rows = dc.query("create table t(a int)", False)
7
print("no problems")
8
except BaseException as e:
9
print('caught exception:', str(e))
Copied!
In one terminal, start the dolt sql-server:
1
$ dolt sql-server --host 0.0.0.0 --port=3000 --user dolt --config ./config.yml
Copied!
In another, run the python script.
1
$ python sqltest.py
2
no problems
Copied!
In this case "no problems" is actually bad, since we expected the server to return an error.

Fixing the Bug

I highly recommend using an IDE like Goland especially when debugging larger projects.
After poking around in the code, we see that the config file containing user permissions is used to create a new sqlengine.
1
serverConf.Address = hostPort
2
serverConf.Auth = userAuth
3
serverConf.ConnReadTimeout = readTimeout
4
serverConf.ConnWriteTimeout = writeTimeout
5
serverConf.MaxConnections = serverConfig.MaxConnections()
6
serverConf.TLSConfig = tlsConfig
7
serverConf.RequireSecureTransport = serverConfig.RequireSecureTransport()
8
sqlEngine, err := engine.NewSqlEngine(ctx, mrEnv, engine.FormatTabular, "", serverConfig.AutoCommit())
Copied!
For some reason, the NewSqlEngine constructor creates a new authenticator using auth.None, which always gives users full permissions. Instead, we should be passing in the authenticator already created that is based on permissions specified in the config file.
1
// NewSqlEngine returns a SqlEngine
2
func NewSqlEngine(
3
ctx context.Context,
4
mrEnv *env.MultiRepoEnv,
5
format PrintResultFormat,
6
initialDb string,
7
+ au auth.Auth,
8
autocommit bool) (*SqlEngine, error) {
9
- au := new(auth.None)
Copied!
The method call to NewSqlEngine now looks like this:
1
sqlEngine, err := engine.NewSqlEngine(ctx, mrEnv, engine.FormatTabular, "", serverConf.Auth, serverConfig.AutoCommit())
Copied!

Testing

After reinstalling dolt and running the python script, we get an exception as expected.
1
$ python sqltest.py
2
caught exception: 1105 (HY000): not authorized: user does not have permission: write
Copied!
A better way to test this is to use a bats tests, which are located in ~/dolt_workspace/dolt/integration-tests/bats. You can install bats through npm
1
$ npm install -g bats
Copied!
This test basically creates a config file (with the read-only flag set to true), starts a dolt sql-server using the config file, sends a query to create a table, and checks to see if that table was created. So, it's an automated way to do everything we did earlier.
1
@test "sql-server: read-only flag prevents modification" {
2
skiponwindows "Has dependencies that are missing on the Jenkins Windows installation."
3
cd repo1
4
DEFAULT_DB="$1"
5
let PORT="$ % (65536-1024) + 1024"
6
cat >config.yml <<EOF
7
log_level: debug
8
user:
9
name: dolt
10
listener:
11
host: "0.0.0.0"
12
port: $PORT
13
behavior:
14
read_only: true
15
EOF
16
dolt sql-server --host 0.0.0.0 --port=$PORT --user dolt --config ./config.yml &
17
SERVER_PID=$!
18
wait_for_connection $PORT 5000
19
# No tables at the start
20
run dolt ls
21
[ "$status" -eq 0 ]
22
[[ "$output" =~ "No tables in working set" ]] || false
23
# attempt to create table (autocommit on), expect either some exception
24
server_query repo1 1 "CREATE TABLE i_should_not_exist (
25
c0 INT
26
)" "" "not authorized: user does not have permission: write"
27
# Expect that there are still no tables
28
run dolt ls
29
[ "$status" -eq 0 ]
30
[[ "$output" =~ "No tables in working set" ]] || false
31
}
Copied!
Then, I ran the test using this shell script placed in the ~/dolt_workspace/dolt directory:
1
#!/bin/bash
2
cd go/cmd/dolt && go install . && cd -
3
cd go/cmd/git-dolt && go install . && cd -
4
cd go/cmd/git-dolt-smudge && go install . && cd -
5
cd go/store/cmd/noms && go install . && cd -
6
cd integration-tests/bats && bats sql-server.bats && cd -
Copied!
As expected, this test passes.
1
$ test.sh
2
...
3
✓ sql-server: read-only flag prevents modification
4
...
Copied!

Submit Changes

Use git to commit and push our changes.
If you are unfamiliar with how to create a Pull Request, follow the instructions here.
Export as PDF
Copy link
Edit on GitHub