Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RLS Policies #132

Merged
merged 1 commit into from
May 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 26 additions & 6 deletions internal/migration_acceptance_tests/acceptance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"database/sql"
"fmt"
"reflect"
"testing"

"github.com/google/uuid"
Expand Down Expand Up @@ -42,7 +43,9 @@ type (
planFactory func(ctx context.Context, connPool sqldb.Queryable, tempDbFactory tempdb.Factory, newSchemaDDL []string, opts ...diff.PlanOpt) (diff.Plan, error)

acceptanceTestCase struct {
name string
name string
// roles is a list of roles that should be created before the DDL is applied
roles []string
Comment on lines +47 to +48
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thought: I wonder if we should make it possible to define roles in schema somehow. Since they're global I figure that would erode the "you're only applying a single schema" paradigm we have, but it feels like a shame that roles have to be defined outside of pg-schema-diff.

oldSchemaDDL []string
newSchemaDDL []string

Expand Down Expand Up @@ -88,12 +91,16 @@ func (suite *acceptanceTestSuite) runTestCases(acceptanceTestCases []acceptanceT
suite.Run("vanilla", func() {
suite.runSubtest(tc, tc.vanillaExpectations, nil)
})
suite.Run("with data packing (and ignoring column order)", func() {
suite.runSubtest(tc, tc.dataPackingExpectations, []diff.PlanOpt{
diff.WithDataPackNewTables(),
diff.WithLogger(log.SimpleLogger()),
// Only run the data packing test if there are expectations for it. We should strip out the embedded
// data packing tests and make them their own tests to simplify the test suite.
if !reflect.DeepEqual(tc.dataPackingExpectations, expectations{}) {
suite.Run("with data packing (and ignoring column order)", func() {
suite.runSubtest(tc, tc.dataPackingExpectations, []diff.PlanOpt{
diff.WithDataPackNewTables(),
diff.WithLogger(log.SimpleLogger()),
})
})
})
}
})
}
}
Expand All @@ -106,6 +113,19 @@ func (suite *acceptanceTestSuite) runSubtest(tc acceptanceTestCase, expects expe
expects.outputState = tc.newSchemaDDL
}

// Create roles since they are global
rootDb, err := sql.Open("pgx", suite.pgEngine.GetPostgresDatabaseDSN())
suite.Require().NoError(err)
defer rootDb.Close()
for _, r := range tc.roles {
_, err := rootDb.Exec(fmt.Sprintf("CREATE ROLE %s", r))
suite.Require().NoError(err)
}
defer func() {
// This will drop the roles (and attempt to reset other cluster-level state)
suite.Require().NoError(pgengine.ResetInstance(context.Background(), rootDb))
}()

// Apply old schema DDL to old DB
oldDb, err := suite.pgEngine.CreateDatabase()
suite.Require().NoError(err)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,6 @@ var backCompatAcceptanceTestCases = []acceptanceTestCase{
},
}

func (suite *acceptanceTestSuite) TestBackCompatAcceptanceTestCases() {
func (suite *acceptanceTestSuite) TestBackCompatTestCases() {
suite.runTestCases(backCompatAcceptanceTestCases)
}
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,6 @@ var checkConstraintCases = []acceptanceTestCase{
},
}

func (suite *acceptanceTestSuite) TestCheckConstraintAcceptanceTestCases() {
func (suite *acceptanceTestSuite) TestCheckConstraintTestCases() {
suite.runTestCases(checkConstraintCases)
}
2 changes: 1 addition & 1 deletion internal/migration_acceptance_tests/column_cases_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -945,6 +945,6 @@ var columnAcceptanceTestCases = []acceptanceTestCase{
},
}

func (suite *acceptanceTestSuite) TestColumnAcceptanceTestCases() {
func (suite *acceptanceTestSuite) TestColumnTestCases() {
suite.runTestCases(columnAcceptanceTestCases)
}
4 changes: 2 additions & 2 deletions internal/migration_acceptance_tests/enum_cases_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,6 @@ var enumAcceptanceTestCases = []acceptanceTestCase{
},
}

func (s *acceptanceTestSuite) TestEnumTestCases() {
s.runTestCases(enumAcceptanceTestCases)
func (suite *acceptanceTestSuite) TestEnumTestCases() {
suite.runTestCases(enumAcceptanceTestCases)
}
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,6 @@ var extensionAcceptanceTestCases = []acceptanceTestCase{
},
}

func (suite *acceptanceTestSuite) TestExtensionAcceptanceTestCases() {
func (suite *acceptanceTestSuite) TestExtensionTestCases() {
suite.runTestCases(extensionAcceptanceTestCases)
}
2 changes: 1 addition & 1 deletion internal/migration_acceptance_tests/function_cases_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,6 @@ var functionAcceptanceTestCases = []acceptanceTestCase{
},
}

func (suite *acceptanceTestSuite) TestFunctionAcceptanceTestCases() {
func (suite *acceptanceTestSuite) TestFunctionTestCases() {
suite.runTestCases(functionAcceptanceTestCases)
}
2 changes: 1 addition & 1 deletion internal/migration_acceptance_tests/index_cases_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -803,6 +803,6 @@ var indexAcceptanceTestCases = []acceptanceTestCase{
},
}

func (suite *acceptanceTestSuite) TestIndexAcceptanceTestCases() {
func (suite *acceptanceTestSuite) TestIndexTestCases() {
suite.runTestCases(indexAcceptanceTestCases)
}
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,6 @@ var localPartitionIndexAcceptanceTestCases = []acceptanceTestCase{
},
}

func (suite *acceptanceTestSuite) TestLocalPartitionIndexAcceptanceTestCases() {
func (suite *acceptanceTestSuite) TestLocalPartitionIndexTestCases() {
suite.runTestCases(localPartitionIndexAcceptanceTestCases)
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,6 @@ var namedSchemaAcceptanceTestCases = []acceptanceTestCase{
},
}

func (suite *acceptanceTestSuite) TestNamedSchemaAcceptanceTestCases() {
func (suite *acceptanceTestSuite) TestNamedSchemaTestCases() {
suite.runTestCases(namedSchemaAcceptanceTestCases)
}
Original file line number Diff line number Diff line change
Expand Up @@ -1245,6 +1245,6 @@ var partitionedIndexAcceptanceTestCases = []acceptanceTestCase{
},
}

func (suite *acceptanceTestSuite) TestPartitionedIndexAcceptanceTestCases() {
func (suite *acceptanceTestSuite) TestPartitionedIndexTestCases() {
suite.runTestCases(partitionedIndexAcceptanceTestCases)
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,13 @@ var partitionedTableAcceptanceTestCases = []acceptanceTestCase{
UNIQUE (foo, bar)
) PARTITION BY LIST (foo);
ALTER TABLE foobar REPLICA IDENTITY FULL;
ALTER TABLE foobar ENABLE ROW LEVEL SECURITY;
ALTER TABLE foobar FORCE ROW LEVEL SECURITY;
CREATE TABLE foobar_1 PARTITION OF foobar FOR VALUES IN ('foo_1');
ALTER TABLE foobar_1 REPLICA IDENTITY DEFAULT ;
ALTER TABLE foobar_1 ENABLE ROW LEVEL SECURITY;
CREATE TABLE foobar_2 PARTITION OF foobar FOR VALUES IN ('foo_2');
ALTER TABLE foobar_2 FORCE ROW LEVEL SECURITY;
CREATE TABLE foobar_3 PARTITION OF foobar FOR VALUES IN ('foo_3');
-- partitioned indexes
CREATE UNIQUE INDEX foobar_unique_idx ON foobar(foo, bar);
Expand Down Expand Up @@ -59,10 +63,17 @@ var partitionedTableAcceptanceTestCases = []acceptanceTestCase{
UNIQUE (foo, bar)
) PARTITION BY LIST (foo);
ALTER TABLE foobar REPLICA IDENTITY FULL;
ALTER TABLE foobar ENABLE ROW LEVEL SECURITY;
ALTER TABLE foobar FORCE ROW LEVEL SECURITY;
-- partitions
ALTER TABLE foobar REPLICA IDENTITY FULL;
ALTER TABLE foobar ENABLE ROW LEVEL SECURITY;
ALTER TABLE foobar FORCE ROW LEVEL SECURITY;
CREATE TABLE foobar_1 PARTITION OF foobar FOR VALUES IN ('foo_1');
ALTER TABLE foobar_1 REPLICA IDENTITY DEFAULT ;
ALTER TABLE foobar_1 ENABLE ROW LEVEL SECURITY;
CREATE TABLE foobar_2 PARTITION OF foobar FOR VALUES IN ('foo_2');
ALTER TABLE foobar_2 FORCE ROW LEVEL SECURITY;
CREATE TABLE foobar_3 PARTITION OF foobar FOR VALUES IN ('foo_3');
-- partitioned indexes
CREATE UNIQUE INDEX foobar_unique_idx ON foobar(foo, bar);
Expand Down Expand Up @@ -98,7 +109,7 @@ var partitionedTableAcceptanceTestCases = []acceptanceTestCase{
},
},
{
name: "Create partitioned table with shared primary key",
name: "Create partitioned table with shared primary key and RLS enabled globally",
oldSchemaDDL: nil,
newSchemaDDL: []string{
`
Expand All @@ -113,6 +124,9 @@ var partitionedTableAcceptanceTestCases = []acceptanceTestCase{
UNIQUE (foo, bar)
) PARTITION BY LIST (foo);
ALTER TABLE schema_1."Foobar" REPLICA IDENTITY FULL;

ALTER TABLE schema_1."Foobar" ENABLE ROW LEVEL SECURITY;
ALTER TABLE schema_1."Foobar" FORCE ROW LEVEL SECURITY;

-- partitions
CREATE SCHEMA schema_2;
Expand Down Expand Up @@ -145,6 +159,9 @@ var partitionedTableAcceptanceTestCases = []acceptanceTestCase{
) PARTITION BY LIST (foo);
ALTER TABLE schema_1."Foobar" REPLICA IDENTITY FULL;

ALTER TABLE schema_1."Foobar" ENABLE ROW LEVEL SECURITY;
ALTER TABLE schema_1."Foobar" FORCE ROW LEVEL SECURITY;

-- partitions
CREATE SCHEMA schema_2;
CREATE TABLE schema_2."FOOBAR_1" PARTITION OF schema_1."Foobar"(
Expand All @@ -165,7 +182,7 @@ var partitionedTableAcceptanceTestCases = []acceptanceTestCase{
},
},
{
name: "Create partitioned table with local primary keys",
name: "Create partitioned table with local primary keys and RLS enabled locally",
oldSchemaDDL: nil,
newSchemaDDL: []string{
`
Expand All @@ -182,9 +199,11 @@ var partitionedTableAcceptanceTestCases = []acceptanceTestCase{
bar NOT NULL,
PRIMARY KEY (foo, id)
) FOR VALUES IN ('foo_1');
ALTER TABLE "FOOBAR_1" ENABLE ROW LEVEL SECURITY;
CREATE TABLE foobar_2 PARTITION OF "Foobar"(
PRIMARY KEY (foo, bar)
) FOR VALUES IN ('foo_2');
ALTER TABLE foobar_2 FORCE ROW LEVEL SECURITY;
CREATE TABLE foobar_3 PARTITION OF "Foobar"(
PRIMARY KEY (foo, fizz),
UNIQUE (foo, bar)
Expand Down Expand Up @@ -334,6 +353,80 @@ var partitionedTableAcceptanceTestCases = []acceptanceTestCase{
diff.MigrationHazardTypeCorrectness,
},
},
{
name: "Enable RLS of parent and children",
oldSchemaDDL: []string{
`
CREATE TABLE foobar(
id INT,
foo VARCHAR(255),
PRIMARY KEY (foo, id)
) PARTITION BY LIST (foo);

-- partitions
CREATE TABLE foobar_1 PARTITION OF foobar FOR VALUES IN ('foo_1');
CREATE TABLE foobar_2 PARTITION OF foobar FOR VALUES IN ('foo_2');
CREATE TABLE foobar_3 PARTITION OF foobar FOR VALUES IN ('foo_3');
`,
},
newSchemaDDL: []string{
`
CREATE TABLE foobar(
id INT,
foo VARCHAR(255),
PRIMARY KEY (foo, id)
) PARTITION BY LIST (foo);
ALTER TABLE foobar ENABLE ROW LEVEL SECURITY;
ALTER TABLE foobar FORCE ROW LEVEL SECURITY;
-- partitions
CREATE TABLE foobar_1 PARTITION OF foobar FOR VALUES IN ('foo_1');
ALTER TABLE foobar_1 ENABLE ROW LEVEL SECURITY;
CREATE TABLE foobar_2 PARTITION OF foobar FOR VALUES IN ('foo_2');
ALTER TABLE foobar_2 FORCE ROW LEVEL SECURITY;
CREATE TABLE foobar_3 PARTITION OF foobar FOR VALUES IN ('foo_3');
`,
},
expectedHazardTypes: []diff.MigrationHazardType{
diff.MigrationHazardTypeAuthzUpdate,
},
},
{
name: "Disable RLS of parent and children",
oldSchemaDDL: []string{
`
CREATE TABLE foobar(
id INT,
foo VARCHAR(255),
PRIMARY KEY (foo, id)
) PARTITION BY LIST (foo);
ALTER TABLE foobar ENABLE ROW LEVEL SECURITY;
ALTER TABLE foobar FORCE ROW LEVEL SECURITY;
-- partitions
CREATE TABLE foobar_1 PARTITION OF foobar FOR VALUES IN ('foo_1');
ALTER TABLE foobar_1 ENABLE ROW LEVEL SECURITY;
CREATE TABLE foobar_2 PARTITION OF foobar FOR VALUES IN ('foo_2');
ALTER TABLE foobar_2 FORCE ROW LEVEL SECURITY;
CREATE TABLE foobar_3 PARTITION OF foobar FOR VALUES IN ('foo_3');
`,
},
newSchemaDDL: []string{
`
CREATE TABLE foobar(
id INT,
foo VARCHAR(255),
PRIMARY KEY (foo, id)
) PARTITION BY LIST (foo);

-- partitions
CREATE TABLE foobar_1 PARTITION OF foobar FOR VALUES IN ('foo_1');
CREATE TABLE foobar_2 PARTITION OF foobar FOR VALUES IN ('foo_2');
CREATE TABLE foobar_3 PARTITION OF foobar FOR VALUES IN ('foo_3');
`,
},
expectedHazardTypes: []diff.MigrationHazardType{
diff.MigrationHazardTypeAuthzUpdate,
},
},
{
name: "Alter table: New primary key, new unique constraint, dropped unique constraint, change column types, delete partitioned index, new partitioned index, delete local index, add local index, validate check constraint, validate FK, delete FK",
oldSchemaDDL: []string{
Expand Down Expand Up @@ -1248,6 +1341,6 @@ var partitionedTableAcceptanceTestCases = []acceptanceTestCase{
},
}

func (suite *acceptanceTestSuite) TestPartitionedTableAcceptanceTestCases() {
func (suite *acceptanceTestSuite) TestPartitionedTableTestCases() {
suite.runTestCases(partitionedTableAcceptanceTestCases)
}
Loading
Loading