|
6 | 6 | "context"
|
7 | 7 | "database/sql"
|
8 | 8 | sqldriver "database/sql/driver"
|
| 9 | + "errors" |
9 | 10 | "fmt"
|
10 | 11 | "log"
|
11 | 12 |
|
@@ -76,6 +77,14 @@ func isReady(ctx context.Context, c dktest.ContainerInfo) bool {
|
76 | 77 | return true
|
77 | 78 | }
|
78 | 79 |
|
| 80 | +func mustRun(t *testing.T, d database.Driver, statements []string) { |
| 81 | + for _, statement := range statements { |
| 82 | + if err := d.Run(strings.NewReader(statement)); err != nil { |
| 83 | + t.Fatal(err) |
| 84 | + } |
| 85 | + } |
| 86 | +} |
| 87 | + |
79 | 88 | func Test(t *testing.T) {
|
80 | 89 | dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) {
|
81 | 90 | ip, port, err := c.FirstPort()
|
@@ -309,6 +318,141 @@ func TestWithSchema(t *testing.T) {
|
309 | 318 | })
|
310 | 319 | }
|
311 | 320 |
|
| 321 | +func TestFailToCreateTableWithoutPermissions(t *testing.T) { |
| 322 | + dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) { |
| 323 | + ip, port, err := c.FirstPort() |
| 324 | + if err != nil { |
| 325 | + t.Fatal(err) |
| 326 | + } |
| 327 | + |
| 328 | + addr := pgConnectionString(ip, port) |
| 329 | + |
| 330 | + // Check that opening the postgres connection returns NilVersion |
| 331 | + p := &Postgres{} |
| 332 | + |
| 333 | + d, err := p.Open(addr) |
| 334 | + |
| 335 | + if err != nil { |
| 336 | + t.Fatal(err) |
| 337 | + } |
| 338 | + |
| 339 | + defer func() { |
| 340 | + if err := d.Close(); err != nil { |
| 341 | + t.Error(err) |
| 342 | + } |
| 343 | + }() |
| 344 | + |
| 345 | + // create user who is not the owner. Although we're concatenating strings in an sql statement it should be fine |
| 346 | + // since this is a test environment and we're not expecting to the pgPassword to be malicious |
| 347 | + mustRun(t, d, []string{ |
| 348 | + "CREATE USER not_owner WITH ENCRYPTED PASSWORD '" + pgPassword + "'", |
| 349 | + "CREATE SCHEMA barfoo AUTHORIZATION postgres", |
| 350 | + "GRANT USAGE ON SCHEMA barfoo TO not_owner", |
| 351 | + "REVOKE CREATE ON SCHEMA barfoo FROM PUBLIC", |
| 352 | + "REVOKE CREATE ON SCHEMA barfoo FROM not_owner", |
| 353 | + }) |
| 354 | + |
| 355 | + // re-connect using that schema |
| 356 | + d2, err := p.Open(fmt.Sprintf("postgres://not_owner:%s@%v:%v/postgres?sslmode=disable&search_path=barfoo", |
| 357 | + pgPassword, ip, port)) |
| 358 | + |
| 359 | + defer func() { |
| 360 | + if d2 == nil { |
| 361 | + return |
| 362 | + } |
| 363 | + if err := d2.Close(); err != nil { |
| 364 | + t.Fatal(err) |
| 365 | + } |
| 366 | + }() |
| 367 | + |
| 368 | + var e *database.Error |
| 369 | + if !errors.As(err, &e) || err == nil { |
| 370 | + t.Fatal("Unexpected error, want permission denied error. Got: ", err) |
| 371 | + } |
| 372 | + |
| 373 | + if !strings.Contains(e.OrigErr.Error(), "permission denied for schema barfoo") { |
| 374 | + t.Fatal(e) |
| 375 | + } |
| 376 | + }) |
| 377 | +} |
| 378 | + |
| 379 | +func TestCheckBeforeCreateTable(t *testing.T) { |
| 380 | + dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) { |
| 381 | + ip, port, err := c.FirstPort() |
| 382 | + if err != nil { |
| 383 | + t.Fatal(err) |
| 384 | + } |
| 385 | + |
| 386 | + addr := pgConnectionString(ip, port) |
| 387 | + |
| 388 | + // Check that opening the postgres connection returns NilVersion |
| 389 | + p := &Postgres{} |
| 390 | + |
| 391 | + d, err := p.Open(addr) |
| 392 | + |
| 393 | + if err != nil { |
| 394 | + t.Fatal(err) |
| 395 | + } |
| 396 | + |
| 397 | + defer func() { |
| 398 | + if err := d.Close(); err != nil { |
| 399 | + t.Error(err) |
| 400 | + } |
| 401 | + }() |
| 402 | + |
| 403 | + // create user who is not the owner. Although we're concatenating strings in an sql statement it should be fine |
| 404 | + // since this is a test environment and we're not expecting to the pgPassword to be malicious |
| 405 | + mustRun(t, d, []string{ |
| 406 | + "CREATE USER not_owner WITH ENCRYPTED PASSWORD '" + pgPassword + "'", |
| 407 | + "CREATE SCHEMA barfoo AUTHORIZATION postgres", |
| 408 | + "GRANT USAGE ON SCHEMA barfoo TO not_owner", |
| 409 | + "GRANT CREATE ON SCHEMA barfoo TO not_owner", |
| 410 | + }) |
| 411 | + |
| 412 | + // re-connect using that schema |
| 413 | + d2, err := p.Open(fmt.Sprintf("postgres://not_owner:%s@%v:%v/postgres?sslmode=disable&search_path=barfoo", |
| 414 | + pgPassword, ip, port)) |
| 415 | + |
| 416 | + if err != nil { |
| 417 | + t.Fatal(err) |
| 418 | + } |
| 419 | + |
| 420 | + if err := d2.Close(); err != nil { |
| 421 | + t.Fatal(err) |
| 422 | + } |
| 423 | + |
| 424 | + // revoke privileges |
| 425 | + mustRun(t, d, []string{ |
| 426 | + "REVOKE CREATE ON SCHEMA barfoo FROM PUBLIC", |
| 427 | + "REVOKE CREATE ON SCHEMA barfoo FROM not_owner", |
| 428 | + }) |
| 429 | + |
| 430 | + // re-connect using that schema |
| 431 | + d3, err := p.Open(fmt.Sprintf("postgres://not_owner:%s@%v:%v/postgres?sslmode=disable&search_path=barfoo", |
| 432 | + pgPassword, ip, port)) |
| 433 | + |
| 434 | + if err != nil { |
| 435 | + t.Fatal(err) |
| 436 | + } |
| 437 | + |
| 438 | + version, _, err := d3.Version() |
| 439 | + |
| 440 | + if err != nil { |
| 441 | + t.Fatal(err) |
| 442 | + } |
| 443 | + |
| 444 | + if version != database.NilVersion { |
| 445 | + t.Fatal("Unexpected version, want database.NilVersion. Got: ", version) |
| 446 | + } |
| 447 | + |
| 448 | + defer func() { |
| 449 | + if err := d3.Close(); err != nil { |
| 450 | + t.Fatal(err) |
| 451 | + } |
| 452 | + }() |
| 453 | + }) |
| 454 | +} |
| 455 | + |
312 | 456 | func TestParallelSchema(t *testing.T) {
|
313 | 457 | dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) {
|
314 | 458 | ip, port, err := c.FirstPort()
|
@@ -375,10 +519,6 @@ func TestParallelSchema(t *testing.T) {
|
375 | 519 | })
|
376 | 520 | }
|
377 | 521 |
|
378 |
| -func TestWithInstance(t *testing.T) { |
379 |
| - |
380 |
| -} |
381 |
| - |
382 | 522 | func TestPostgres_Lock(t *testing.T) {
|
383 | 523 | dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) {
|
384 | 524 | ip, port, err := c.FirstPort()
|
|
0 commit comments