Skip to content
Closed
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
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
name: Set up Go
uses: actions/setup-go@v2
with:
go-version: '1.20'
go-version: '1.23'
-
name: Import GPG key
id: import_gpg
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:

strategy:
matrix:
pgversion: [15, 14, 13, 12, 11]
pgversion: [16, 15, 14, 13, 12, 11]

env:
PGVERSION: ${{ matrix.pgversion }}
Expand Down
154 changes: 148 additions & 6 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,149 @@
./*.tfstate
.terraform/
.terraform.lock.hcl*
*.log
.*.swp
tests/docker-compose.*.yml
terraform-provider-postgresql

### JetBrains+all template
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839

# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf

# AWS User-specific
.idea/**/aws.xml

# Generated files
.idea/**/contentModel.xml

# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml

# Gradle
.idea/**/gradle.xml
.idea/**/libraries

# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr

# CMake
cmake-build-*/

# Mongo Explorer plugin
.idea/**/mongoSettings.xml

# File-based project format
*.iws

# IntelliJ
out/

# mpeltonen/sbt-idea plugin
.idea_modules/

# JIRA plugin
atlassian-ide-plugin.xml

# Cursive Clojure plugin
.idea/replstate.xml

# SonarLint plugin
.idea/sonarlint/

# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties

# Editor-based Rest Client
.idea/httpRequests

# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser


### Linux template
*~

# temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden*

# KDE directory preferences
.directory

# Linux trash folder which might appear on any partition or disk
.Trash-*

# .nfs files are created when an open file is removed but is still being accessed
.nfs*

### Go template
# If you prefer the allow list template instead of the deny list, see community template:
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
#
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib

# Test binary, built with `go test -c`
*.test

# Output of the go coverage tool, specifically when used with LiteIDE
*.out

# Dependency directories (remove the comment below to include it)
# vendor/

# Go workspace file
go.work

### Windows template
# Windows thumbnail cache files
Thumbs.db
Thumbs.db:encryptable
ehthumbs.db
ehthumbs_vista.db

# Dump file
*.stackdump

# Folder config file
[Dd]esktop.ini

# Recycle Bin used on file shares
$RECYCLE.BIN/

# Windows Installer files
*.cab
*.msi
*.msix
*.msm
*.msp

# Windows shortcuts
*.lnk

.terraform
.terraform.lock.hcl
terraform.tfstate*
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Requirements
------------

- [Terraform](https://www.terraform.io/downloads.html) 0.12.x
- [Go](https://golang.org/doc/install) 1.16 (to build the provider plugin)
- [Go](https://golang.org/doc/install) 1.21 (to build the provider plugin)

Building The Provider
---------------------
Expand Down
13 changes: 13 additions & 0 deletions examples/issues/407/dev.tfrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# See https://www.terraform.io/cli/config/config-file#development-overrides-for-provider-developers
# Use `go build -o ./examples/issues/407/postgresql/terraform-provider-postgresql` in the project root to build the provider.
# Then run terraform in this example directory.

# terraform init
# TF_CLI_CONFIG_FILE=dev.tfrc terraform apply

provider_installation {
dev_overrides {
"cyrilgdn/postgresql" = "./postgresql"
}
direct {}
}
25 changes: 25 additions & 0 deletions examples/issues/407/test.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
terraform {
required_version = ">= 1.0"

required_providers {
postgresql = {
source = "cyrilgdn/postgresql"
version = "~>1"
}
}
}

provider "postgresql" {
superuser = false
port = 25432
username = "rds"
password = "rds"
sslmode = "disable"
}

resource "postgresql_role" "test_role_with_createrole_self_grant" {
name = "test_role_with_createrole_self_grant"
parameters {
createrole_self_grant = "set,inherit"
}
}
5 changes: 5 additions & 0 deletions postgresql/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ const (
featurePubWithoutTruncate
featureFunction
featureServer
featureCreateRoleSelfGrant
)

var (
Expand Down Expand Up @@ -115,6 +116,10 @@ var (
featureServer: semver.MustParseRange(">=10.0.0"),

featureDatabaseOwnerRole: semver.MustParseRange(">=15.0.0"),

// New privileges rules in version 16
// https://www.postgresql.org/docs/16/release-16.html#RELEASE-16-PRIVILEGES
featureCreateRoleSelfGrant: semver.MustParseRange(">=16.0.0"),
}
)

Expand Down
37 changes: 36 additions & 1 deletion postgresql/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ package postgresql

import (
"context"
"database/sql"
"fmt"
"github.com/hashicorp/terraform-plugin-log/tflog"
"os"
"regexp"

"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"

"github.com/blang/semver"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
Expand Down Expand Up @@ -363,6 +365,39 @@ func providerConfigure(d *schema.ResourceData) (interface{}, error) {
}
}

err := checkCreateRoleSelfGrant(config)
if err != nil {
return nil, err
}

client := config.NewClient(d.Get("database").(string))
return client, nil
}

func checkCreateRoleSelfGrant(config Config) error {
client := config.NewClient("postgres")
connect, err := client.Connect()
if err != nil {
return err
}

username := config.Username

if connect.featureSupported(featureCreateRoleSelfGrant) && !config.Superuser {
var paramValue string
query := `SELECT coalesce(replace(jsonb_path_query_first(to_jsonb(rolconfig),'$[*] ? (@ like_regex "^createrole_self_grant=")')::TEXT,'%[1]s=',''), '') FROM pg_catalog.pg_roles WHERE rolname = $1`
err := connect.QueryRow(query, username).Scan(&paramValue)
switch {
case err == sql.ErrNoRows:
// They don't have a parameter, just skip
break
case err != nil:
tflog.Debug(context.Background(), fmt.Sprintf("User %s parameters cannot be checked: %v", username, err))
}
if !regexp.MustCompile(`^set\s*,\s*inherit$|^inherit\s*,\s*set$`).MatchString(paramValue) {
msg := fmt.Sprintf("Provider user %[1]s has not configured property 'createrole_self_grant' properly. Creating new roles will not create non admin grants by default. You can set it by \"ALTER ROLE '%[1]s' SET createrole_self_grant 'set, inherit';\"", username)
tflog.Warn(context.Background(), msg)
}
}
return nil
}
31 changes: 31 additions & 0 deletions postgresql/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,37 @@ func TestProvider_impl(t *testing.T) {
var _ *schema.Provider = Provider()
}

func TestAccProviderSetCreateRoleSelfGrant(t *testing.T) {
skipIfNotAcc(t)

config := getTestConfig(t)
client := config.NewClient("postgres")
db, err := client.Connect()
if err != nil {
t.Fatal(err)
}

if db.featureSupported(featureCreateRoleSelfGrant) {
t.Skipf("Skip tests for unsuported feature %d in Postgres %s", featureCreateRoleSelfGrant, db.version)
}

// Create NON superuser role
if _, err = db.Exec("CREATE ROLE rds_srg LOGIN CREATEDB CREATEROLE PASSWORD 'rds_srg'"); err != nil {
t.Fatalf("could not create role for test user paramaters: %v", err)
}
defer func() {
_, _ = db.Exec("DROP ROLE rds_srg")
}()

provider := Provider()
provider.Configure(context.Background(), terraform.NewResourceConfigRaw(
map[string]interface{}{
"username": "rds_srg",
"password": "rds_srg",
},
))
}

func testAccPreCheck(t *testing.T) {
var host string
if host = os.Getenv("PGHOST"); host == "" {
Expand Down
13 changes: 11 additions & 2 deletions postgresql/resource_postgresql_database_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,17 @@ resource postgresql_database "test_db" {
resource.TestCheckResourceAttr("postgresql_database.test_db", "name", "test_db"),
resource.TestCheckResourceAttr("postgresql_database.test_db", "owner", "test_owner"),

// check if connected user does not have test_owner granted anymore.
checkUserMembership(t, dsn, config.Username, "test_owner", false),
func(state *terraform.State) error {
connect, _ := config.NewClient("postgres").Connect()
if connect.featureSupported(featureCreateRoleSelfGrant) {
// in PG 16 all created roles have creator grant with admin option
checkUserMembership(t, dsn, config.Username, "test_owner", true)
} else {
// check if connected user does not have test_owner granted anymore.
checkUserMembership(t, dsn, config.Username, "test_owner", false)
}
return nil
},
),
},
},
Expand Down
17 changes: 13 additions & 4 deletions postgresql/resource_postgresql_default_privileges_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,16 +187,25 @@ resource "postgresql_default_privileges" "test_ro" {
resource.TestCheckResourceAttr("postgresql_default_privileges.test_ro", "privileges.#", "1"),
resource.TestCheckResourceAttr("postgresql_default_privileges.test_ro", "privileges.0", "SELECT"),

// check if connected user does not have test_owner granted anymore.
checkUserMembership(t, dsn, config.Username, "test_owner", false),
func(state *terraform.State) error {
connect, _ := config.NewClient("postgres").Connect()
if connect.featureSupported(featureCreateRoleSelfGrant) {
// in PG 16 all created roles have creator grant with admin option by default
checkUserMembership(t, dsn, config.Username, "test_owner", true)
} else {
// check if connected user does not have test_owner granted anymore.
checkUserMembership(t, dsn, config.Username, "test_owner", false)
}
return nil
},
),
},
},
})
}

// Test the case where we define default priviliges without specifying a schema. These
// priviliges should apply to newly created resources for the named role in all schema.
// Test the case where we define default privileges without specifying a schema. These
// privileges should apply to newly created resources for the named role in all schema.
func TestAccPostgresqlDefaultPrivileges_NoSchema(t *testing.T) {
skipIfNotAcc(t)

Expand Down
Loading