Files
zitadel/cmd/initialise/verify_user_test.go
T
0a18aba91c fix(database): skip CREATE USER when role exists to avoid password in Postgres logs (#12538)
<!-- CURSOR_AGENT_PR_BODY_BEGIN -->
## Summary

When `zitadel init` runs on every Helm upgrade/re-deploy, `VerifyUser`
always executed `CREATE USER ... WITH PASSWORD '...'`. If the role
already existed, PostgreSQL returned `42710` and logged the full
statement—including the plaintext password—even though ZITADEL swallowed
that error.

This mirrors the existing `VerifyDatabase` catalog check: query
`pg_roles` first and skip creation when the role exists. Also stops
mutating the package-level `createUserStmt` when appending `WITH
PASSWORD`.

Fixes #12178

## Changes

- `cmd/initialise/verify_user.go`: check `SELECT EXISTS(... FROM
pg_roles ...)` before `CREATE USER`; build password clause on a local
statement copy
- `cmd/initialise/verify_user_test.go`: cover catalog skip,
catalog-check failure, and create paths with the new query

## Test plan

- [x] `go test ./cmd/initialise/...` (passed)
- [ ] Re-run init against an existing role and confirm Postgres logs no
longer contain `CREATE USER ... WITH PASSWORD`
<!-- CURSOR_AGENT_PR_BODY_END -->

<div><a
href="https://cursor.com/agents/bc-bc514793-d275-4d91-a71b-1b7566668b65?cursor_ref=pr_footer&cursor_cta=open_in_web"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/assets/images/open-in-web-light.png"><img
alt="Open in Web" width="114" height="28"
src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a>&nbsp;<a
href="https://cursor.com/background-agent?bcId=bc-bc514793-d275-4d91-a71b-1b7566668b65&cursor_ref=pr_footer&cursor_cta=open_in_cursor"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img
alt="Open in Cursor" width="131" height="28"
src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a>&nbsp;</div>

Co-authored-by: Cursor Agent <[email protected]>
Co-authored-by: Silvan <[email protected]>
2026-08-05 09:28:16 +02:00

150 lines
4.1 KiB
Go

package initialise
import (
"context"
"database/sql"
"database/sql/driver"
"errors"
"testing"
)
func Test_verifyUser(t *testing.T) {
err := ReadStmts()
if err != nil {
t.Errorf("unable to read stmts: %v", err)
t.FailNow()
}
type args struct {
db db
username string
password string
}
tests := []struct {
name string
args args
targetErr error
}{
{
name: "doesn't exists, create fails",
args: args{
db: prepareDB(t,
expectQuery("SELECT current_user", nil, []string{"current_user"}, [][]driver.Value{
{"postgres"},
}),
expectQuery("SELECT EXISTS(SELECT 1 FROM pg_roles WHERE rolname = $1)", nil, []string{"exists"}, [][]driver.Value{
{false},
}, "zitadel-user"),
expectExec("-- replace zitadel-user with the name of the user\nCREATE USER \"zitadel-user\"", sql.ErrTxDone),
),
username: "zitadel-user",
password: "",
},
targetErr: sql.ErrTxDone,
},
{
name: "correct without password",
args: args{
db: prepareDB(t,
expectQuery("SELECT current_user", nil, []string{"current_user"}, [][]driver.Value{
{"postgres"},
}),
expectQuery("SELECT EXISTS(SELECT 1 FROM pg_roles WHERE rolname = $1)", nil, []string{"exists"}, [][]driver.Value{
{false},
}, "zitadel-user"),
expectExec("-- replace zitadel-user with the name of the user\nCREATE USER \"zitadel-user\"", nil),
),
username: "zitadel-user",
password: "",
},
targetErr: nil,
},
{
name: "correct with password",
args: args{
db: prepareDB(t,
expectQuery("SELECT current_user", nil, []string{"current_user"}, [][]driver.Value{
{"postgres"},
}),
expectQuery("SELECT EXISTS(SELECT 1 FROM pg_roles WHERE rolname = $1)", nil, []string{"exists"}, [][]driver.Value{
{false},
}, "zitadel-user"),
expectExec("-- replace zitadel-user with the name of the user\nCREATE USER \"zitadel-user\" WITH PASSWORD 'password'", nil),
),
username: "zitadel-user",
password: "password",
},
targetErr: nil,
},
{
name: "correct with password containing percent and quote",
args: args{
db: prepareDB(t,
expectQuery("SELECT current_user", nil, []string{"current_user"}, [][]driver.Value{
{"postgres"},
}),
expectQuery("SELECT EXISTS(SELECT 1 FROM pg_roles WHERE rolname = $1)", nil, []string{"exists"}, [][]driver.Value{
{false},
}, "zitadel-user"),
expectExec("-- replace zitadel-user with the name of the user\nCREATE USER \"zitadel-user\" WITH PASSWORD 'p%''ass'", nil),
),
username: "zitadel-user",
password: "p%'ass",
},
targetErr: nil,
},
{
name: "already exists in catalog, skip creation",
args: args{
db: prepareDB(t,
expectQuery("SELECT current_user", nil, []string{"current_user"}, [][]driver.Value{
{"postgres"},
}),
expectQuery("SELECT EXISTS(SELECT 1 FROM pg_roles WHERE rolname = $1)", nil, []string{"exists"}, [][]driver.Value{
{true},
}, "zitadel-user"),
),
username: "zitadel-user",
password: "password",
},
targetErr: nil,
},
{
name: "catalog check fails",
args: args{
db: prepareDB(t,
expectQuery("SELECT current_user", nil, []string{"current_user"}, [][]driver.Value{
{"postgres"},
}),
expectQuery("SELECT EXISTS(SELECT 1 FROM pg_roles WHERE rolname = $1)", sql.ErrConnDone, []string{"exists"}, [][]driver.Value{}, "zitadel-user"),
),
username: "zitadel-user",
password: "password",
},
targetErr: sql.ErrConnDone,
},
{
name: "same user, skip create",
args: args{
db: prepareDB(t,
expectQuery("SELECT current_user", nil, []string{"current_user"}, [][]driver.Value{
{"zitadel-user"},
}),
),
username: "zitadel-user",
},
targetErr: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := VerifyUser(tt.args.username, tt.args.password)(context.Background(), tt.args.db.db); !errors.Is(err, tt.targetErr) {
t.Errorf("VerifyUser() error = %v, want: %v", err, tt.targetErr)
}
if err := tt.args.db.mock.ExpectationsWereMet(); err != nil {
t.Error(err)
}
})
}
}