test: stabilize TestIntegrations/SessionRecordingModes by isolating per-subtest user/role state (#64033)

* test: stabilize TestIntegrations/SessionRecordingModes by isolating per-subtest user/role state

Fixes #48043

`TestIntegrations/SessionRecordingModes` was flaky because the subtests
reused the same Teleport user and role while switching recording mode
between `strict` and `best_effort`. Under cache propagation
delay/staleness, one subtest could observe the previous subtest’s role
state, causing incorrect behavior (for example, `BestEffortMode` failing
with `ssh: could not start shell` as if strict mode was still active).

For local reproduction, I introduced a temporary debug cache fault to
drop role update events after initial cache population. With
`StrictMode` run before `BestEffortMode`, that reliably reproduced the
failure by forcing stale role reads in later subtests.

The fix removes shared mutable identity state from the test:
- create a unique Teleport user per mode subtest
- create a unique role per mode subtest

This makes each subtest evaluate recording mode against isolated auth
state, instead of depending on cache timing/order.

Validation:
- with the temporary cache fault enabled, the old test shape reproduced the failure while the isolated user/role version passed
- after removing the temporary fault, `go test ./integration -run 'TestIntegrations/SessionRecordingModes' -count=50` passes with the final code

* stop loading test keys into local SSH agent
This commit is contained in:
Nic Klaassen
2026-02-21 02:50:09 +00:00
committed by GitHub
parent 2fa1a2454d
commit b2e150e7d7
3 changed files with 18 additions and 11 deletions
-1
View File
@@ -54,7 +54,6 @@ func NewFixture(t *testing.T) *Fixture {
fixture.Priv, fixture.Pub, err = testauthority.GenerateKeyPair()
require.NoError(t, err)
// Find AllocatePortsNum free listening ports to use.
fixture.Me, err = user.Current()
require.NoError(t, err)
+1
View File
@@ -1525,6 +1525,7 @@ func (i *TeleInstance) NewUnauthenticatedClient(cfg ClientConfig) (tc *client.Te
Stdout: cfg.Stdout,
NonInteractive: true,
DisableSSHResumption: cfg.DisableSSHResumption,
AddKeysToAgent: client.AddKeysToAgentNo,
}
// JumpHost turns on jump host mode
+17 -10
View File
@@ -889,15 +889,16 @@ func testSessionRecordingModes(t *testing.T, suite *integrationTestSuite) {
// startSession starts an interactive session, users must terminate the
// session by typing "exit" in the terminal.
startSession := func(username string) (*Terminal, chan error) {
startSession := func(login, teleportUser string) (*Terminal, chan error) {
term := NewTerminal(250)
errCh := make(chan error)
go func() {
cl, err := teleport.NewClient(helpers.ClientConfig{
Login: username,
Cluster: helpers.Site,
Host: Host,
Login: login,
TeleportUser: teleportUser,
Cluster: helpers.Site,
Host: Host,
})
if err != nil {
errCh <- trace.Wrap(err)
@@ -946,10 +947,15 @@ func testSessionRecordingModes(t *testing.T, suite *integrationTestSuite) {
} {
t.Run(name, func(t *testing.T) {
// Setup user and session recording mode.
username := suite.Me.Username
role, err := types.NewRole("devs", types.RoleSpecV6{
login := suite.Me.Username
// Use unique Teleport user and role names per subtest to avoid
// cross-test cache/state reuse when role mappings are updated.
id := uuid.NewString()[:8]
teleportUser := fmt.Sprintf("%s-%s", strings.ToLower(name), id)
roleName := fmt.Sprintf("devs-%s", id)
role, err := types.NewRole(roleName, types.RoleSpecV6{
Allow: types.RoleConditions{
Logins: []string{username},
Logins: []string{login},
NodeLabels: types.Labels{types.Wildcard: []string{types.Wildcard}},
},
Options: types.RoleOptions{
@@ -959,7 +965,7 @@ func testSessionRecordingModes(t *testing.T, suite *integrationTestSuite) {
},
})
require.NoError(t, err)
require.NoError(t, helpers.SetupUser(teleport.Process, username, []types.Role{role}))
require.NoError(t, helpers.SetupUser(teleport.Process, teleportUser, []types.Role{role}))
t.Run("BeforeStartFailure", func(t *testing.T) {
// Enable disk failure.
@@ -967,7 +973,7 @@ func testSessionRecordingModes(t *testing.T, suite *integrationTestSuite) {
defer disableDiskFailure()
// Start session.
term, errCh := startSession(username)
term, errCh := startSession(login, teleportUser)
if test.expectSessionFailure {
waitSessionTermination(t, errCh, require.Error)
return
@@ -990,7 +996,7 @@ func testSessionRecordingModes(t *testing.T, suite *integrationTestSuite) {
t.Run("MidSessionFailure", func(t *testing.T) {
// Start session.
term, errCh := startSession(username)
term, errCh := startSession(login, teleportUser)
// Guarantee the session started properly.
select {
@@ -1016,6 +1022,7 @@ func testSessionRecordingModes(t *testing.T, suite *integrationTestSuite) {
term.Type("exit\n\r")
waitSessionTermination(t, errCh, require.NoError)
})
})
}
}