Skip to content

fix(enterprise/dbcrypt): do not skip deleted users when encrypting or deleting #9694

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

Merged
merged 11 commits into from
Sep 15, 2023
Next Next commit
add some more logging to test
  • Loading branch information
johnstcn committed Sep 15, 2023
commit 355b2c1059f4637f1b526008fe9abd7a69753396
59 changes: 51 additions & 8 deletions enterprise/cli/server_dbcrypt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"database/sql"
"encoding/base64"
"strings"
"testing"

"github.com/google/uuid"
Expand Down Expand Up @@ -43,12 +44,26 @@ func TestServerDBCrypt(t *testing.T) {

// Populate the database with some unencrypted data.
users := genData(t, db, 10)
dumpUsers(t, sqlDB, "NOT ENCRYPTED")

// Setup an initial cipher
// Setup an initial cipher A
keyA := mustString(t, 32)
cipherA, err := dbcrypt.NewCiphers([]byte(keyA))
require.NoError(t, err)

// Create an encrypted database
cryptdb, err := dbcrypt.New(ctx, db, cipherA...)
require.NoError(t, err)

// Populate the database with some encrypted data using cipher A.
users = append(users, genData(t, cryptdb, 10)...)
dumpUsers(t, sqlDB, "PARTIALLY ENCRYPTED A")

// Validate that newly created users were encrypted with cipher A
for _, usr := range users[10:] {
requireEncryptedWithCipher(ctx, t, db, cipherA[0], usr.ID)
}

// Encrypt all the data with the initial cipher.
inv, _ := newCLI(t, "server", "dbcrypt", "rotate",
"--postgres-url", connectionURL,
Expand All @@ -60,18 +75,12 @@ func TestServerDBCrypt(t *testing.T) {
err = inv.Run()
require.NoError(t, err)

dumpUsers(t, sqlDB, "ENCRYPTED A")
// Validate that all existing data has been encrypted with cipher A.
for _, usr := range users {
requireEncryptedWithCipher(ctx, t, db, cipherA[0], usr.ID)
}

// Create an encrypted database
cryptdb, err := dbcrypt.New(ctx, db, cipherA...)
require.NoError(t, err)

// Populate the database with some encrypted data using cipher A.
users = append(users, genData(t, cryptdb, 10)...)

// Re-encrypt all existing data with a new cipher.
keyB := mustString(t, 32)
cipherBA, err := dbcrypt.NewCiphers([]byte(keyB), []byte(keyA))
Expand All @@ -89,6 +98,7 @@ func TestServerDBCrypt(t *testing.T) {
require.NoError(t, err)

// Validate that all data has been re-encrypted with cipher B.
dumpUsers(t, sqlDB, "ENCRYPTED B")
for _, usr := range users {
requireEncryptedWithCipher(ctx, t, db, cipherBA[0], usr.ID)
}
Expand Down Expand Up @@ -135,6 +145,7 @@ func TestServerDBCrypt(t *testing.T) {
}

// Validate that all data has been decrypted.
dumpUsers(t, sqlDB, "DECRYPTED")
for _, usr := range users {
requireEncryptedWithCipher(ctx, t, db, &nullCipher{}, usr.ID)
}
Expand All @@ -156,6 +167,7 @@ func TestServerDBCrypt(t *testing.T) {
require.NoError(t, err)

// Validate that all data has been re-encrypted with cipher C.
dumpUsers(t, sqlDB, "ENCRYPTED C")
for _, usr := range users {
requireEncryptedWithCipher(ctx, t, db, cipherC[0], usr.ID)
}
Expand All @@ -172,6 +184,7 @@ func TestServerDBCrypt(t *testing.T) {
require.NoError(t, err)

// Assert that no user links remain.
dumpUsers(t, sqlDB, "DELETED")
for _, usr := range users {
userLinks, err := db.GetUserLinksByUserID(ctx, usr.ID)
require.NoError(t, err, "failed to get user links for user %s", usr.ID)
Expand Down Expand Up @@ -215,6 +228,36 @@ func genData(t *testing.T, db database.Store, n int) []database.User {
return users
}

func dumpUsers(t *testing.T, db *sql.DB, header string) {
t.Logf("%s %s %s", strings.Repeat("=", 20), header, strings.Repeat("=", 20))
rows, err := db.QueryContext(context.Background(), `select u.id, u.status, u.deleted, ul.oauth_access_token_key_id as uloatkid, ul.oauth_refresh_token_key_id as ulortkid, gal.oauth_access_token_key_id as galoatkid, gal.oauth_refresh_token_key_id as galortkid from users u left outer join user_links ul on u.id = ul.user_id left outer join git_auth_links gal on u.id = gal.user_id;`)
require.NoError(t, err)
defer rows.Close()
for rows.Next() {
var (
id string
status string
deleted bool
UlOatKid sql.NullString
UlOrtKid sql.NullString
GalOatKid sql.NullString
GalOrtKid sql.NullString
)
require.NoError(t, rows.Scan(
&id,
&status,
&deleted,
&UlOatKid,
&UlOrtKid,
&GalOatKid,
&GalOrtKid,
))
t.Logf("user: id:%s status:%-9s deleted:%-5t ul_kids{at:%-7s rt:%-7s} gal_kids{at:%-7s rt:%-7s}",
id, status, deleted, UlOatKid.String, UlOrtKid.String, GalOatKid.String, GalOrtKid.String,
)
}
}

func mustString(t *testing.T, n int) string {
t.Helper()
s, err := cryptorand.String(n)
Expand Down