diff --git a/test/e2e/helpers/assert.go b/test/e2e/helpers/assert.go index d8d74ab..f7f6266 100644 --- a/test/e2e/helpers/assert.go +++ b/test/e2e/helpers/assert.go @@ -107,7 +107,7 @@ func GetRemoteUserSnapshot(baseURL string, userID int) (*userMigration.RemoteUse nil, http.StatusOK, map[string]string{ - "X-Sync-API-Key": DefaultSyncAPIKey, + "X-Sync-API-Key": SyncAPIKey(), "X-Sync-Node": "e2e-assert", }, &resp, diff --git a/test/e2e/helpers/cluster.go b/test/e2e/helpers/cluster.go index e6e5479..76a6643 100644 --- a/test/e2e/helpers/cluster.go +++ b/test/e2e/helpers/cluster.go @@ -19,19 +19,40 @@ const ( DefaultCNPort = 3100 DefaultOVPort = 3101 - DefaultSessionSecret = "user-migration-e2e-session-secret" DefaultCNDBFileName = "cn.db" DefaultOVDBFileName = "ov.db" DefaultCNLogFileName = "cn.log" DefaultOVLogFileName = "ov.log" DefaultCNSessionName = "cn_session" DefaultOVSessionName = "ov_session" - DefaultSyncAPIKey = "e2e-sync-key" DefaultRootUsername = "root" - DefaultRootPassword = "Password123!" defaultNodeReadyTimout = 45 * time.Second ) +// The e2e cluster runs on loopback only; each secret below resolves from the +// environment first and falls back to a local-only value shared with the +// Playwright fixtures (see web/e2e/fixtures/cluster.ts). +func RootPassword() string { + if password := strings.TrimSpace(os.Getenv("E2E_ROOT_PASSWORD")); password != "" { + return password + } + return "e2e-local-root-pass" +} + +func SessionSecret() string { + if secret := strings.TrimSpace(os.Getenv("E2E_SESSION_SECRET")); secret != "" { + return secret + } + return "e2e-local-session-secret" +} + +func SyncAPIKey() string { + if key := strings.TrimSpace(os.Getenv("E2E_SYNC_API_KEY")); key != "" { + return key + } + return "e2e-local-sync-key" +} + type NodeProcess struct { Name string Port int @@ -115,11 +136,11 @@ func PrepareEnvironment(repoRoot, artifactRoot, binaryPath, scenarioName string) return nil, err } - if err := SetupRoot(cnClient, DefaultRootUsername, DefaultRootPassword); err != nil { + if err := SetupRoot(cnClient, DefaultRootUsername, RootPassword()); err != nil { _ = cluster.Stop() return nil, fmt.Errorf("setup CN root: %w", err) } - if err := SetupRoot(ovClient, DefaultRootUsername, DefaultRootPassword); err != nil { + if err := SetupRoot(ovClient, DefaultRootUsername, RootPassword()); err != nil { _ = cluster.Stop() return nil, fmt.Errorf("setup OV root: %w", err) } @@ -151,25 +172,25 @@ func PrepareEnvironment(repoRoot, artifactRoot, binaryPath, scenarioName string) return nil, err } - if err := Login(cnClient, DefaultRootUsername, DefaultRootPassword); err != nil { + if err := Login(cnClient, DefaultRootUsername, RootPassword()); err != nil { _ = cluster.Stop() return nil, fmt.Errorf("login CN root: %w", err) } - if err := Login(ovClient, DefaultRootUsername, DefaultRootPassword); err != nil { + if err := Login(ovClient, DefaultRootUsername, RootPassword()); err != nil { _ = cluster.Stop() return nil, fmt.Errorf("login OV root: %w", err) } - if err := ConfigureCNRegionSync(cnClient, cluster.CN.BaseURL, cluster.OV.BaseURL, DefaultSyncAPIKey); err != nil { + if err := ConfigureCNRegionSync(cnClient, cluster.CN.BaseURL, cluster.OV.BaseURL, SyncAPIKey()); err != nil { _ = cluster.Stop() return nil, fmt.Errorf("configure CN region sync: %w", err) } - if err := ConfigureOVRegionSync(ovClient, cluster.CN.BaseURL, DefaultSyncAPIKey); err != nil { + if err := ConfigureOVRegionSync(ovClient, cluster.CN.BaseURL, SyncAPIKey()); err != nil { _ = cluster.Stop() return nil, fmt.Errorf("configure OV region sync: %w", err) } - if err := WaitOptionApplied(cluster.OV.BaseURL, DefaultSyncAPIKey, 5, 20*time.Second); err != nil { + if err := WaitOptionApplied(cluster.OV.BaseURL, SyncAPIKey(), 5, 20*time.Second); err != nil { _ = cluster.Stop() return nil, fmt.Errorf("wait OV migration API ready: %w", err) } @@ -272,7 +293,7 @@ func (c *Cluster) startNode(name string, port int, dbPath, sessionName, nodeType cmd.Env = mergeEnv(os.Environ(), map[string]string{ "PORT": fmt.Sprintf("%d", port), "SQLITE_PATH": dbPath, - "SESSION_SECRET": DefaultSessionSecret, + "SESSION_SECRET": SessionSecret(), "SESSION_NAME": sessionName, "SESSION_SECURE": "false", "SESSION_SAMESITE": "strict", diff --git a/test/e2e/user_migration_test.go b/test/e2e/user_migration_test.go index d121653..85c225a 100644 --- a/test/e2e/user_migration_test.go +++ b/test/e2e/user_migration_test.go @@ -224,7 +224,7 @@ func TestUserMigrationE2E_ScanPagination(t *testing.T) { func TestUserMigrationE2E_RootPermission(t *testing.T) { env := newEnvironment(t) - adminClient := createAndLoginManagedUser(t, env.Cluster.CN.BaseURL, env.CNClient, "migration-admin", helpers.DefaultRootPassword, common.RoleAdminUser) + adminClient := createAndLoginManagedUser(t, env.Cluster.CN.BaseURL, env.CNClient, "migration-admin", helpers.RootPassword(), common.RoleAdminUser) var listResp simpleResponse require.NoError(t, adminClient.GetJSON("/api/user-migrations/batches", 200, &listResp)) @@ -707,7 +707,7 @@ func createManagedUsers(t *testing.T, client *helpers.APIClient, prefix string, var resp simpleResponse require.NoError(t, client.PostJSON("/api/user/", map[string]any{ "username": username, - "password": helpers.DefaultRootPassword, + "password": helpers.RootPassword(), "display_name": displayName, "email": email, "role": role, @@ -775,7 +775,7 @@ func convertRemoteUserToSynced(t *testing.T, ovBaseURL string, sourceUserID, rem }, 200, map[string]string{ - "X-Sync-API-Key": helpers.DefaultSyncAPIKey, + "X-Sync-API-Key": helpers.SyncAPIKey(), "X-Sync-Node": "e2e-test", }, &resp, diff --git a/web/e2e/fixtures/cluster.ts b/web/e2e/fixtures/cluster.ts index d382766..ed17f72 100644 --- a/web/e2e/fixtures/cluster.ts +++ b/web/e2e/fixtures/cluster.ts @@ -33,9 +33,9 @@ export const clusterRunDir = path.join(artifactRoot, 'runs', 'playwright-ui'); export const cnBaseURL = 'http://127.0.0.1:3100'; export const ovBaseURL = 'http://127.0.0.1:3101'; export const rootUsername = 'root'; -export const rootPassword = 'Password123!'; +export const rootPassword = process.env.E2E_ROOT_PASSWORD ?? 'e2e-local-root-pass'; export const adminUsername = 'playwright-admin'; -export const adminPassword = 'Password123!'; +export const adminPassword = process.env.E2E_ADMIN_PASSWORD ?? 'e2e-local-admin-pass'; export type ClusterMetadata = { serverPid: number; diff --git a/web/e2e/utils/process.js b/web/e2e/utils/process.js index ef0d2fd..d5f7680 100644 --- a/web/e2e/utils/process.js +++ b/web/e2e/utils/process.js @@ -66,10 +66,13 @@ function waitForExit(child, timeoutMs) { } function killWindowsProcessTree(pid) { - if (!pid) return Promise.resolve(); + const numericPid = Number(pid); + if (!Number.isInteger(numericPid) || numericPid <= 0) { + return Promise.resolve(); + } return new Promise((resolve) => { - const killer = spawn('taskkill', ['/PID', String(pid), '/T', '/F'], { + const killer = spawn('taskkill', ['/PID', String(numericPid), '/T', '/F'], { stdio: 'ignore', });