-
Notifications
You must be signed in to change notification settings - Fork 32
fix: use target database user for embedded postgres in plan command (#303) #338
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -209,11 +209,19 @@ func CreateDesiredStateProvider(config *PlanConfig) (postgres.DesiredStateProvid | |
| // CreateEmbeddedPostgresForPlan creates a temporary embedded PostgreSQL instance | ||
| // for validating the desired state schema. The instance should be stopped by the caller. | ||
| func CreateEmbeddedPostgresForPlan(config *PlanConfig, pgVersion postgres.PostgresVersion) (*postgres.EmbeddedPostgres, error) { | ||
| // Start embedded PostgreSQL with matching version | ||
| if config.User == "" { | ||
| return nil, fmt.Errorf("target database user must not be empty when creating embedded postgres") | ||
| } | ||
|
|
||
| // Start embedded PostgreSQL with matching version. | ||
| // Use the target database username so that role references match between | ||
| // the desired state (embedded) and current state (target database). | ||
| // This ensures ALTER DEFAULT PRIVILEGES FOR ROLE <user> works correctly | ||
| // and that implicit owner roles match the target database. (issue #303) | ||
| embeddedConfig := &postgres.EmbeddedPostgresConfig{ | ||
| Version: pgVersion, | ||
| Database: "pgschema_temp", | ||
| Username: "pgschema", | ||
| Username: config.User, | ||
| Password: "pgschema", | ||
| } | ||
|
Comment on lines
221
to
226
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No guard against empty
Consider adding a defensive guard before constructing if config.User == "" {
return nil, fmt.Errorf("target database user must not be empty when creating embedded postgres")
}
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added in 9937ab6. |
||
| embeddedPG, err := postgres.StartEmbeddedPostgres(embeddedConfig) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| ALTER DEFAULT PRIVILEGES FOR ROLE testuser IN SCHEMA public GRANT SELECT ON TABLES TO demouser; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| -- Create roles for testing | ||
| DO $$ | ||
| BEGIN | ||
| IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'demouser') THEN | ||
| CREATE ROLE demouser; | ||
| END IF; | ||
| END $$; | ||
|
|
||
| -- Grant default privileges with explicit FOR ROLE (issue #303) | ||
| ALTER DEFAULT PRIVILEGES FOR ROLE testuser IN SCHEMA public GRANT SELECT ON TABLES TO demouser; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| -- Create roles for testing | ||
| DO $$ | ||
| BEGIN | ||
| IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'demouser') THEN | ||
| CREATE ROLE demouser; | ||
| END IF; | ||
| END $$; | ||
|
|
||
| -- No default privileges configured |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| { | ||
| "version": "1.0.0", | ||
| "pgschema_version": "1.7.3", | ||
| "created_at": "1970-01-01T00:00:00Z", | ||
| "source_fingerprint": { | ||
| "hash": "965b1131737c955e24c7f827c55bd78e4cb49a75adfd04229e0ba297376f5085" | ||
| }, | ||
| "groups": [ | ||
| { | ||
| "steps": [ | ||
| { | ||
| "sql": "ALTER DEFAULT PRIVILEGES FOR ROLE testuser IN SCHEMA public GRANT SELECT ON TABLES TO demouser;", | ||
| "type": "default_privilege", | ||
| "operation": "create", | ||
| "path": "default_privileges.testuser.TABLES.demouser" | ||
| } | ||
| ] | ||
| } | ||
| ] | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| ALTER DEFAULT PRIVILEGES FOR ROLE testuser IN SCHEMA public GRANT SELECT ON TABLES TO demouser; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| Plan: 1 to add. | ||
|
|
||
| Summary by type: | ||
| default privileges: 1 to add | ||
|
|
||
| Default privileges: | ||
| + demouser | ||
|
|
||
| DDL to be executed: | ||
| -------------------------------------------------- | ||
|
|
||
| ALTER DEFAULT PRIVILEGES FOR ROLE testuser IN SCHEMA public GRANT SELECT ON TABLES TO demouser; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The behavior change (embedded DB username now derived from
config.User) isn’t directly covered by a regression test that would have failed before this fix. Consider adding an integration test forplanthat uses a desired-state file containingALTER DEFAULT PRIVILEGES FOR ROLE <target user> ...(and creates any required roles), and asserts the plan command succeeds; this would fail when the embedded username was hardcoded topgschemaand pass with this change.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The password suggestion is incorrect. The embedded postgres is a fresh local instance — its password is independent of the target database. The username matters because PostgreSQL uses it for role ownership attribution (
pg_get_userbyid(defaclrole)). The password has no semantic meaning here; it is just auth to a throwaway instance.Regarding test coverage: valid observation. The integration test uses
sharedEmbeddedPGas the provider (bypassingCreateEmbeddedPostgresForPlan), so it would not have caught the hardcoded username directly. However, a true end-to-end test spinning up a separate embedded PG with a mismatched user would be complex and slow. The diff test verifiesFOR ROLEworks correctly at the IR level.