From 7f2ab3b536a2a95d50f1b5008c6bd420daa6e892 Mon Sep 17 00:00:00 2001 From: Jared Bunting Date: Wed, 18 Oct 2023 13:06:05 -0400 Subject: [PATCH 1/7] Add SECURITY LABEL provider to acceptance test postgres db. --- tests/build/Dockerfile | 6 ++ tests/build/dummy_seclabel/Makefile | 13 ++++ .../dummy_seclabel/dummy_seclabel--1.0.sql | 8 +++ tests/build/dummy_seclabel/dummy_seclabel.c | 60 +++++++++++++++++++ .../dummy_seclabel/dummy_seclabel.control | 4 ++ tests/docker-compose.yml | 5 +- 6 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 tests/build/Dockerfile create mode 100644 tests/build/dummy_seclabel/Makefile create mode 100644 tests/build/dummy_seclabel/dummy_seclabel--1.0.sql create mode 100644 tests/build/dummy_seclabel/dummy_seclabel.c create mode 100644 tests/build/dummy_seclabel/dummy_seclabel.control diff --git a/tests/build/Dockerfile b/tests/build/Dockerfile new file mode 100644 index 00000000..e132f836 --- /dev/null +++ b/tests/build/Dockerfile @@ -0,0 +1,6 @@ +FROM postgres:${PGVERSION:-latest} + +RUN apt-get update && apt-get install -y build-essential postgresql-server-dev-all +COPY dummy_seclabel /opt/dummy_seclabel +WORKDIR /opt/dummy_seclabel +RUN make diff --git a/tests/build/dummy_seclabel/Makefile b/tests/build/dummy_seclabel/Makefile new file mode 100644 index 00000000..3447a688 --- /dev/null +++ b/tests/build/dummy_seclabel/Makefile @@ -0,0 +1,13 @@ +# src/test/modules/dummy_seclabel/Makefile + +MODULES = dummy_seclabel +PGFILEDESC = "dummy_seclabel - regression testing of the SECURITY LABEL statement" + +EXTENSION = dummy_seclabel +DATA = dummy_seclabel--1.0.sql + +REGRESS = dummy_seclabel + +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) diff --git a/tests/build/dummy_seclabel/dummy_seclabel--1.0.sql b/tests/build/dummy_seclabel/dummy_seclabel--1.0.sql new file mode 100644 index 00000000..5939e930 --- /dev/null +++ b/tests/build/dummy_seclabel/dummy_seclabel--1.0.sql @@ -0,0 +1,8 @@ +/* src/test/modules/dummy_seclabel/dummy_seclabel--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION dummy_seclabel" to load this file. \quit + +CREATE FUNCTION dummy_seclabel_dummy() + RETURNS pg_catalog.void +AS 'MODULE_PATHNAME' LANGUAGE C; diff --git a/tests/build/dummy_seclabel/dummy_seclabel.c b/tests/build/dummy_seclabel/dummy_seclabel.c new file mode 100644 index 00000000..fea8d679 --- /dev/null +++ b/tests/build/dummy_seclabel/dummy_seclabel.c @@ -0,0 +1,60 @@ +/* + * dummy_seclabel.c + * + * Dummy security label provider. + * + * This module does not provide anything worthwhile from a security + * perspective, but allows regression testing independent of platform-specific + * features like SELinux. + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + */ +#include "postgres.h" + +#include "commands/seclabel.h" +#include "fmgr.h" +#include "miscadmin.h" +#include "utils/rel.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(dummy_seclabel_dummy); + +static void +dummy_object_relabel(const ObjectAddress *object, const char *seclabel) +{ + if (seclabel == NULL || + strcmp(seclabel, "unclassified") == 0 || + strcmp(seclabel, "classified") == 0) + return; + + if (strcmp(seclabel, "secret") == 0 || + strcmp(seclabel, "top secret") == 0) + { + if (!superuser()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("only superuser can set '%s' label", seclabel))); + return; + } + ereport(ERROR, + (errcode(ERRCODE_INVALID_NAME), + errmsg("'%s' is not a valid security label", seclabel))); +} + +void +_PG_init(void) +{ + register_label_provider("dummy", dummy_object_relabel); +} + +/* + * This function is here just so that the extension is not completely empty + * and the dynamic library is loaded when CREATE EXTENSION runs. + */ +Datum +dummy_seclabel_dummy(PG_FUNCTION_ARGS) +{ + PG_RETURN_VOID(); +} diff --git a/tests/build/dummy_seclabel/dummy_seclabel.control b/tests/build/dummy_seclabel/dummy_seclabel.control new file mode 100644 index 00000000..8c372728 --- /dev/null +++ b/tests/build/dummy_seclabel/dummy_seclabel.control @@ -0,0 +1,4 @@ +comment = 'Test code for SECURITY LABEL feature' +default_version = '1.0' +module_pathname = '$libdir/dummy_seclabel' +relocatable = true diff --git a/tests/docker-compose.yml b/tests/docker-compose.yml index 177994bf..6c212946 100644 --- a/tests/docker-compose.yml +++ b/tests/docker-compose.yml @@ -2,7 +2,8 @@ version: "3" services: postgres: - image: postgres:${PGVERSION:-latest} + build: build +# image: postgres:${PGVERSION:-latest} user: postgres command: - "postgres" @@ -10,6 +11,8 @@ services: - "wal_level=logical" - "-c" - "max_replication_slots=10" + - "-c" + - "shared_preload_libraries=/opt/dummy_seclabel/dummy_seclabel" environment: POSTGRES_PASSWORD: ${PGPASSWORD} ports: From 1deb31b1edf8e348c5fbc2a0ecffb6fcd80aadea Mon Sep 17 00:00:00 2001 From: Jared Bunting Date: Wed, 18 Oct 2023 13:06:23 -0400 Subject: [PATCH 2/7] fix quote ident for objectname and provider --- postgresql/config.go | 2 + postgresql/provider.go | 1 + .../resource_postgresql_security_label.go | 192 ++++++++++++++++ ...resource_postgresql_security_label_test.go | 214 ++++++++++++++++++ .../r/postgresql_security_label.html.markdown | 42 ++++ website/postgresql.erb | 3 + 6 files changed, 454 insertions(+) create mode 100644 postgresql/resource_postgresql_security_label.go create mode 100644 postgresql/resource_postgresql_security_label_test.go create mode 100644 website/docs/r/postgresql_security_label.html.markdown diff --git a/postgresql/config.go b/postgresql/config.go index 0b225323..fd9cbfad 100644 --- a/postgresql/config.go +++ b/postgresql/config.go @@ -45,6 +45,7 @@ const ( featureFunction featureServer featureCreateRoleSelfGrant + featureSecurityLabel ) var ( @@ -120,6 +121,7 @@ var ( // New privileges rules in version 16 // https://www.postgresql.org/docs/16/release-16.html#RELEASE-16-PRIVILEGES featureCreateRoleSelfGrant: semver.MustParseRange(">=16.0.0"), + featureSecurityLabel: semver.MustParseRange(">=11.0.0"), } ) diff --git a/postgresql/provider.go b/postgresql/provider.go index 2743d7b6..af2b435f 100644 --- a/postgresql/provider.go +++ b/postgresql/provider.go @@ -207,6 +207,7 @@ func Provider() *schema.Provider { "postgresql_function": resourcePostgreSQLFunction(), "postgresql_server": resourcePostgreSQLServer(), "postgresql_user_mapping": resourcePostgreSQLUserMapping(), + "postgresql_security_label": resourcePostgreSQLSecurityLabel(), }, DataSourcesMap: map[string]*schema.Resource{ diff --git a/postgresql/resource_postgresql_security_label.go b/postgresql/resource_postgresql_security_label.go new file mode 100644 index 00000000..97bcd088 --- /dev/null +++ b/postgresql/resource_postgresql_security_label.go @@ -0,0 +1,192 @@ +package postgresql + +import ( + "bytes" + "database/sql" + "fmt" + "log" + "regexp" + "strings" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/lib/pq" +) + +const ( + securityLabelObjectNameAttr = "object_name" + securityLabelObjectTypeAttr = "object_type" + securityLabelProviderAttr = "label_provider" + securityLabelLabelAttr = "label" +) + +func resourcePostgreSQLSecurityLabel() *schema.Resource { + return &schema.Resource{ + Create: PGResourceFunc(resourcePostgreSQLSecurityLabelCreate), + Read: PGResourceFunc(resourcePostgreSQLSecurityLabelRead), + Update: PGResourceFunc(resourcePostgreSQLSecurityLabelUpdate), + Delete: PGResourceFunc(resourcePostgreSQLSecurityLabelDelete), + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + + Schema: map[string]*schema.Schema{ + securityLabelObjectNameAttr: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The name of the existing object to apply the security label to", + }, + securityLabelObjectTypeAttr: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The type of the existing object to apply the security label to", + }, + securityLabelProviderAttr: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The provider to apply the security label for", + }, + securityLabelLabelAttr: { + Type: schema.TypeString, + Required: true, + ForceNew: false, + Description: "The label to be applied", + }, + }, + } +} + +func resourcePostgreSQLSecurityLabelCreate(db *DBConnection, d *schema.ResourceData) error { + if !db.featureSupported(featureSecurityLabel) { + return fmt.Errorf( + "security Label is not supported for this Postgres version (%s)", + db.version, + ) + } + log.Printf("[WARN] PostgreSQL security label Create") + label := d.Get(securityLabelLabelAttr).(string) + if err := resourcePostgreSQLSecurityLabelUpdateImpl(db, d, pq.QuoteLiteral(label)); err != nil { + return err + } + + d.SetId(generateSecurityLabelID(d)) + + return resourcePostgreSQLSecurityLabelReadImpl(db, d) +} + +func resourcePostgreSQLSecurityLabelUpdateImpl(db *DBConnection, d *schema.ResourceData, label string) error { + b := bytes.NewBufferString("SECURITY LABEL ") + + objectType := d.Get(securityLabelObjectTypeAttr).(string) + objectName := d.Get(securityLabelObjectNameAttr).(string) + provider := d.Get(securityLabelProviderAttr).(string) + fmt.Fprint(b, " FOR ", pq.QuoteIdentifier(provider)) + fmt.Fprint(b, " ON ", objectType, pq.QuoteIdentifier(objectName)) + fmt.Fprint(b, " IS ", label) + + if _, err := db.Exec(b.String()); err != nil { + log.Printf("[WARN] PostgreSQL security label Create failed %s", err) + return err + } + return nil +} + +func resourcePostgreSQLSecurityLabelRead(db *DBConnection, d *schema.ResourceData) error { + if !db.featureSupported(featureSecurityLabel) { + return fmt.Errorf( + "Security Label is not supported for this Postgres version (%s)", + db.version, + ) + } + log.Printf("[WARN] PostgreSQL security label Read") + + return resourcePostgreSQLSecurityLabelReadImpl(db, d) +} + +func resourcePostgreSQLSecurityLabelReadImpl(db *DBConnection, d *schema.ResourceData) error { + objectType := d.Get(securityLabelObjectTypeAttr).(string) + objectName := d.Get(securityLabelObjectNameAttr).(string) + provider := d.Get(securityLabelProviderAttr).(string) + + txn, err := startTransaction(db.client, "") + if err != nil { + return err + } + defer deferredRollback(txn) + + query := "SELECT objtype, provider, label FROM pg_seclabels WHERE objtype = $1 and objname = $2 and provider = $3" + row := db.QueryRow(query, objectType, quoteIdentifier(objectName), quoteIdentifier(provider)) + + var label string + err = row.Scan(&objectType, &provider, &label) + switch { + case err == sql.ErrNoRows: + log.Printf("[WARN] PostgreSQL security label for (%s '%s') with provider %s not found", objectType, objectName, provider) + d.SetId("") + return nil + case err != nil: + return fmt.Errorf("Error reading security label: %w", err) + } + + d.Set(securityLabelObjectTypeAttr, objectType) + d.Set(securityLabelObjectNameAttr, objectName) + d.Set(securityLabelProviderAttr, provider) + d.Set(securityLabelLabelAttr, label) + d.SetId(generateSecurityLabelID(d)) + + return nil +} + +func resourcePostgreSQLSecurityLabelDelete(db *DBConnection, d *schema.ResourceData) error { + if !db.featureSupported(featureSecurityLabel) { + return fmt.Errorf( + "Security Label is not supported for this Postgres version (%s)", + db.version, + ) + } + log.Printf("[WARN] PostgreSQL security label Delete") + + if err := resourcePostgreSQLSecurityLabelUpdateImpl(db, d, "NULL"); err != nil { + return err + } + + d.SetId("") + + return nil +} + +func resourcePostgreSQLSecurityLabelUpdate(db *DBConnection, d *schema.ResourceData) error { + if !db.featureSupported(featureServer) { + return fmt.Errorf( + "Security Label is not supported for this Postgres version (%s)", + db.version, + ) + } + log.Printf("[WARN] PostgreSQL security label Update") + + label := d.Get(securityLabelLabelAttr).(string) + if err := resourcePostgreSQLSecurityLabelUpdateImpl(db, d, pq.QuoteLiteral(label)); err != nil { + return err + } + + return resourcePostgreSQLSecurityLabelReadImpl(db, d) +} + +func generateSecurityLabelID(d *schema.ResourceData) string { + return strings.Join([]string{ + d.Get(securityLabelProviderAttr).(string), + d.Get(securityLabelObjectTypeAttr).(string), + d.Get(securityLabelObjectNameAttr).(string), + }, ".") +} + +func quoteIdentifier(s string) string { + var result = s + re := regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_]*$`) + if !re.MatchString(s) || s != strings.ToLower(s) { + result = pq.QuoteIdentifier(s) + } + return result +} diff --git a/postgresql/resource_postgresql_security_label_test.go b/postgresql/resource_postgresql_security_label_test.go new file mode 100644 index 00000000..f1701795 --- /dev/null +++ b/postgresql/resource_postgresql_security_label_test.go @@ -0,0 +1,214 @@ +package postgresql + +import ( + "database/sql" + "fmt" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccPostgresqlSecurityLabel_Basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + testCheckCompatibleVersion(t, featureSecurityLabel) + testSuperuserPreCheck(t) + }, + Providers: testAccProviders, + CheckDestroy: testAccCheckPostgresqlSecurityLabelDestroy, + Steps: []resource.TestStep{ + { + Config: testAccPostgresqlSecurityLabelConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckPostgresqlSecurityLabelExists("postgresql_security_label.test_label"), + resource.TestCheckResourceAttr( + "postgresql_security_label.test_label", "object_type", "role"), + resource.TestCheckResourceAttr( + "postgresql_security_label.test_label", "object_name", "security_label_test_role"), + resource.TestCheckResourceAttr( + "postgresql_security_label.test_label", "label_provider", "dummy"), + resource.TestCheckResourceAttr( + "postgresql_security_label.test_label", "label", "secret"), + ), + }, + }, + }) +} + +func TestAccPostgresqlSecurityLabel_Update(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + testCheckCompatibleVersion(t, featureSecurityLabel) + testSuperuserPreCheck(t) + }, + Providers: testAccProviders, + CheckDestroy: testAccCheckPostgresqlSecurityLabelDestroy, + Steps: []resource.TestStep{ + { + Config: testAccPostgresqlSecurityLabelConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckPostgresqlSecurityLabelExists("postgresql_security_label.test_label"), + resource.TestCheckResourceAttr( + "postgresql_security_label.test_label", "object_type", "role"), + resource.TestCheckResourceAttr( + "postgresql_security_label.test_label", "object_name", "security_label_test_role"), + resource.TestCheckResourceAttr( + "postgresql_security_label.test_label", "label_provider", "dummy"), + resource.TestCheckResourceAttr( + "postgresql_security_label.test_label", "label", "secret"), + ), + }, + { + Config: testAccPostgresqlSecurityLabelChanges2, + Check: resource.ComposeTestCheckFunc( + testAccCheckPostgresqlSecurityLabelExists("postgresql_security_label.test_label"), + resource.TestCheckResourceAttr( + "postgresql_security_label.test_label", "label", "top secret"), + ), + }, + { + Config: testAccPostgresqlSecurityLabelChanges3, + Check: resource.ComposeTestCheckFunc( + testAccCheckPostgresqlSecurityLabelExists("postgresql_security_label.test_label"), + resource.TestCheckResourceAttr( + "postgresql_security_label.test_label", "object_name", "security_label_test-role2"), + ), + }, + }, + }) +} + +func checkSecurityLabelExists(txn *sql.Tx, objectType string, objectName string, provider string) (bool, error) { + var _rez bool + err := txn.QueryRow("SELECT TRUE FROM pg_seclabels WHERE objtype = $1 AND objname = $2 AND provider = $3", objectType, quoteIdentifier(objectName), provider).Scan(&_rez) + switch { + case err == sql.ErrNoRows: + return false, nil + case err != nil: + return false, fmt.Errorf("Error reading info about security label: %s", err) + } + + return true, nil +} + +func testAccCheckPostgresqlSecurityLabelDestroy(s *terraform.State) error { + client := testAccProvider.Meta().(*Client) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "postgresql_security_label" { + continue + } + + txn, err := startTransaction(client, "") + if err != nil { + return err + } + defer deferredRollback(txn) + + splitted := strings.Split(rs.Primary.ID, ".") + exists, err := checkSecurityLabelExists(txn, splitted[1], splitted[2], splitted[0]) + + if err != nil { + return fmt.Errorf("Error checking security label%s", err) + } + + if exists { + return fmt.Errorf("Security label still exists after destroy") + } + } + + return nil +} + +func testAccCheckPostgresqlSecurityLabelExists(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Resource not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No ID is set") + } + + objectType, ok := rs.Primary.Attributes[securityLabelObjectTypeAttr] + if !ok { + return fmt.Errorf("No Attribute for object type is set") + } + + objectName, ok := rs.Primary.Attributes[securityLabelObjectNameAttr] + if !ok { + return fmt.Errorf("No Attribute for object name is set") + } + + provider, ok := rs.Primary.Attributes[securityLabelProviderAttr] + if !ok { + return fmt.Errorf("No Attribute for security provider is set") + } + + client := testAccProvider.Meta().(*Client) + txn, err := startTransaction(client, "") + if err != nil { + return err + } + defer deferredRollback(txn) + + exists, err := checkSecurityLabelExists(txn, objectType, objectName, provider) + + if err != nil { + return fmt.Errorf("Error checking security label%s", err) + } + + if !exists { + return fmt.Errorf("Security label not found") + } + + return nil + } +} + +var testAccPostgresqlSecurityLabelConfig = ` +resource "postgresql_role" "test_role" { + name = "security_label_test_role" + login = true + create_database = true +} +resource "postgresql_security_label" "test_label" { + object_type = "role" + object_name = postgresql_role.test_role.name + label_provider = "dummy" + label = "secret" +} +` + +var testAccPostgresqlSecurityLabelChanges2 = ` +resource "postgresql_role" "test_role" { + name = "security_label_test_role" + login = true + create_database = true +} +resource "postgresql_security_label" "test_label" { + object_type = "role" + object_name = postgresql_role.test_role.name + label_provider = "dummy" + label = "top secret" +} +` + +var testAccPostgresqlSecurityLabelChanges3 = ` +resource "postgresql_role" "test_role" { + name = "security_label_test-role2" + login = true + create_database = true +} +resource "postgresql_security_label" "test_label" { + object_type = "role" + object_name = postgresql_role.test_role.name + label_provider = "dummy" + label = "top secret" +} +` diff --git a/website/docs/r/postgresql_security_label.html.markdown b/website/docs/r/postgresql_security_label.html.markdown new file mode 100644 index 00000000..64d4960f --- /dev/null +++ b/website/docs/r/postgresql_security_label.html.markdown @@ -0,0 +1,42 @@ +--- +layout: "postgresql" +page_title: "PostgreSQL: postgresql_grant" +sidebar_current: "docs-postgresql-resource-postgresql_grant" +description: |- + Creates and manages privileges given to a user for a database schema. +--- + +# postgresql\_security\_label + +The ``postgresql_security_label`` resource creates and manages security labels. + +See [PostgreSQL documentation](https://www.postgresql.org/docs/current/sql-security-label.html) + +~> **Note:** This resource needs Postgresql version 11 or above. + +## Usage + +```hcl +resource "postgresql_role" "my_role" { + name = "my_role" + login = true +} + +resource "postgresql_security_label" "workload" { + object_type = "role" + object_name = postgresql_role.my_role.name + label_provider = "pgaadauth" + label = "aadauth,oid=00000000-0000-0000-0000-000000000000,type=service" +} +``` + +## Argument Reference + +* `object_type` - (Required) The PostgreSQL object type to apply this security label to. +* `object_name` - (Required) The name of the object to be labeled. Names of objects that reside in schemas (tables, functions, etc.) can be schema-qualified. +* `label_provider` - (Required) The name of the provider with which this label is to be associated. +* `label` - (Required) The value of the security label. + +## Import + +Security label is an attribute that can be added multiple times, so no import is needed, simply apply again. diff --git a/website/postgresql.erb b/website/postgresql.erb index 5b525a9e..b48358f2 100644 --- a/website/postgresql.erb +++ b/website/postgresql.erb @@ -52,6 +52,9 @@ > postgresql_user_mapping + > + postgresql_security_label + From 4f1956f93684d8b06ac01a43f1f12a19c5b997b3 Mon Sep 17 00:00:00 2001 From: Stanley Zhang Date: Fri, 25 Oct 2024 18:19:29 +1300 Subject: [PATCH 3/7] Apply suggestions from code review Co-authored-by: Cyril Gaudin --- postgresql/resource_postgresql_security_label.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/postgresql/resource_postgresql_security_label.go b/postgresql/resource_postgresql_security_label.go index 97bcd088..1e5fd5bc 100644 --- a/postgresql/resource_postgresql_security_label.go +++ b/postgresql/resource_postgresql_security_label.go @@ -65,9 +65,9 @@ func resourcePostgreSQLSecurityLabelCreate(db *DBConnection, d *schema.ResourceD db.version, ) } - log.Printf("[WARN] PostgreSQL security label Create") + log.Printf("[DEBUG] PostgreSQL security label Create") label := d.Get(securityLabelLabelAttr).(string) - if err := resourcePostgreSQLSecurityLabelUpdateImpl(db, d, pq.QuoteLiteral(label)); err != nil { + if err := resourcePostgreSQLSecurityLabelUpdateImpl(db, d, label); err != nil { return err } @@ -88,7 +88,7 @@ func resourcePostgreSQLSecurityLabelUpdateImpl(db *DBConnection, d *schema.Resou if _, err := db.Exec(b.String()); err != nil { log.Printf("[WARN] PostgreSQL security label Create failed %s", err) - return err + return fmt.Errorf("could not create security label: %w", err) } return nil } @@ -100,7 +100,7 @@ func resourcePostgreSQLSecurityLabelRead(db *DBConnection, d *schema.ResourceDat db.version, ) } - log.Printf("[WARN] PostgreSQL security label Read") + log.Printf("[DEBUG] PostgreSQL security label Read") return resourcePostgreSQLSecurityLabelReadImpl(db, d) } From 59f141d6e72fcf32395f4e980b01b1636e9488b9 Mon Sep 17 00:00:00 2001 From: Stanley Zhang Date: Fri, 25 Oct 2024 18:47:54 +1300 Subject: [PATCH 4/7] Update to reflect what's reviewed --- .../resource_postgresql_security_label.go | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/postgresql/resource_postgresql_security_label.go b/postgresql/resource_postgresql_security_label.go index 1e5fd5bc..626d87fd 100644 --- a/postgresql/resource_postgresql_security_label.go +++ b/postgresql/resource_postgresql_security_label.go @@ -67,7 +67,7 @@ func resourcePostgreSQLSecurityLabelCreate(db *DBConnection, d *schema.ResourceD } log.Printf("[DEBUG] PostgreSQL security label Create") label := d.Get(securityLabelLabelAttr).(string) - if err := resourcePostgreSQLSecurityLabelUpdateImpl(db, d, label); err != nil { + if err := resourcePostgreSQLSecurityLabelUpdateImpl(db, d, pq.QuoteLiteral(label)); err != nil { return err } @@ -116,11 +116,11 @@ func resourcePostgreSQLSecurityLabelReadImpl(db *DBConnection, d *schema.Resourc } defer deferredRollback(txn) - query := "SELECT objtype, provider, label FROM pg_seclabels WHERE objtype = $1 and objname = $2 and provider = $3" + query := "SELECT objtype, provider, objname, label FROM pg_seclabels WHERE objtype = $1 and objname = $2 and provider = $3" row := db.QueryRow(query, objectType, quoteIdentifier(objectName), quoteIdentifier(provider)) - var label string - err = row.Scan(&objectType, &provider, &label) + var label, newObjectName, newProvider string + err = row.Scan(&objectType, &newProvider, &newObjectName, &label) switch { case err == sql.ErrNoRows: log.Printf("[WARN] PostgreSQL security label for (%s '%s') with provider %s not found", objectType, objectName, provider) @@ -130,6 +130,12 @@ func resourcePostgreSQLSecurityLabelReadImpl(db *DBConnection, d *schema.Resourc return fmt.Errorf("Error reading security label: %w", err) } + if quoteIdentifier(objectName) != newObjectName || quoteIdentifier(provider) != newProvider { + // In reality, this should never happen, but if it does, we want to make sure that the state is in sync with the remote system + // This will trigger a TF error saying that the provider has a bug if it ever happens + objectName = newObjectName + provider = newProvider + } d.Set(securityLabelObjectTypeAttr, objectType) d.Set(securityLabelObjectNameAttr, objectName) d.Set(securityLabelProviderAttr, provider) @@ -146,7 +152,7 @@ func resourcePostgreSQLSecurityLabelDelete(db *DBConnection, d *schema.ResourceD db.version, ) } - log.Printf("[WARN] PostgreSQL security label Delete") + log.Printf("[DEBUG] PostgreSQL security label Delete") if err := resourcePostgreSQLSecurityLabelUpdateImpl(db, d, "NULL"); err != nil { return err @@ -164,7 +170,7 @@ func resourcePostgreSQLSecurityLabelUpdate(db *DBConnection, d *schema.ResourceD db.version, ) } - log.Printf("[WARN] PostgreSQL security label Update") + log.Printf("[DEBUG] PostgreSQL security label Update") label := d.Get(securityLabelLabelAttr).(string) if err := resourcePostgreSQLSecurityLabelUpdateImpl(db, d, pq.QuoteLiteral(label)); err != nil { From bc6c1721f554f1b5c47fb0031b5eb7a86be6f444 Mon Sep 17 00:00:00 2001 From: Stanley Zhang Date: Mon, 28 Oct 2024 21:31:52 +1300 Subject: [PATCH 5/7] Pass in PGVersion in test --- tests/docker-compose.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/docker-compose.yml b/tests/docker-compose.yml index 6c212946..6eb18a01 100644 --- a/tests/docker-compose.yml +++ b/tests/docker-compose.yml @@ -2,8 +2,10 @@ version: "3" services: postgres: - build: build -# image: postgres:${PGVERSION:-latest} + build: + context: build + args: + - PGVERSION=${PGVERSION} user: postgres command: - "postgres" From 2258c1cc4ef0c1e575ccaa7bb4daa9b719ab371f Mon Sep 17 00:00:00 2001 From: Stanley Zhang Date: Mon, 28 Oct 2024 22:51:55 +1300 Subject: [PATCH 6/7] Add ARG to Dockerfile --- tests/build/Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/build/Dockerfile b/tests/build/Dockerfile index e132f836..82294f27 100644 --- a/tests/build/Dockerfile +++ b/tests/build/Dockerfile @@ -1,3 +1,4 @@ +ARG PGVERSION FROM postgres:${PGVERSION:-latest} RUN apt-get update && apt-get install -y build-essential postgresql-server-dev-all From b8791826fe7a99ab47245bd20de4603dd04bd680 Mon Sep 17 00:00:00 2001 From: Stanley Zhang Date: Tue, 29 Oct 2024 21:40:22 +1300 Subject: [PATCH 7/7] Make sure the dev library is same as server version --- tests/build/Dockerfile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/build/Dockerfile b/tests/build/Dockerfile index 82294f27..60efcd79 100644 --- a/tests/build/Dockerfile +++ b/tests/build/Dockerfile @@ -1,7 +1,9 @@ ARG PGVERSION FROM postgres:${PGVERSION:-latest} -RUN apt-get update && apt-get install -y build-essential postgresql-server-dev-all +ARG PGVERSION +RUN apt-get update && apt-get install -y build-essential postgresql-server-dev-${PGVERSION:-all} +RUN dpkg -l |grep postgresql COPY dummy_seclabel /opt/dummy_seclabel WORKDIR /opt/dummy_seclabel RUN make