Files
deploy/test/e2e/logout_test.go
zeekayandHanzo Dev 1ab6e799c1 cd: the module is github.com/hanzoai/cd, where it is actually hosted
go.mod still declared `module github.com/hanzoai/deploy` after the repo was
renamed. A Go module path is not cosmetic — it is the resolvable location. So
`go get github.com/hanzoai/cd` could not work, and anything importing this
module had to spell a name that no longer exists at that address. The build log
of v3.6.0 is where it surfaced: the compiler was still emitting
github.com/hanzoai/deploy/cmd/cd/commands.

3541 import paths across 690 .go, 19 .proto, 4 .yaml, 3 .sh, 2 .mod, Procfile
and Makefile. Plus the 62 ghcr.io/hanzoai/deploy image references, moved to
ghcr.io/hanzoai/cd to match hanzo.yml's build target — a distinct string from
the module path, replaced separately so neither could clobber the other.

go mod tidy clean, CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build ./... clean.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-28 21:16:24 -07:00

173 lines
4.3 KiB
Go

package e2e
import (
"testing"
"github.com/stretchr/testify/require"
sessionFixture "github.com/hanzoai/cd/test/e2e/fixture/session"
)
// TestLogoutRevokesToken verifies that after logging out via the /auth/logout endpoint,
// the JWT token is revoked and can no longer be used for API calls.
func TestLogoutRevokesToken(t *testing.T) {
sessionFixture.Given(t).
When().
Login("token1").
GetUserInfo("token1").
ListAccounts("token1").
Then().
ActionShouldSucceed().
When().
Logout("token1").
GetUserInfo("token1").
ListAccounts("token1").
Then().
ActionShouldFail(func(err error) {
require.Contains(t, err.Error(), "token is revoked")
})
}
// TestLogoutDoesNotAffectOtherSessions verifies that revoking one session token
// does not invalidate a different session token for the same user.
func TestLogoutDoesNotAffectOtherSessions(t *testing.T) {
sessionFixture.Given(t).
When().
Login("token1").
Login("token2").
GetUserInfo("token1").
GetUserInfo("token2").
ListAccounts("token1").
Then().
ActionShouldSucceed().
When().
GetUserInfo("token2").
ListAccounts("token2").
Then().
ActionShouldSucceed().
When().
Logout("token1").
GetUserInfo("token1").
ListApplications("token1").
Then().
ActionShouldFail(func(err error) {
require.Contains(t, err.Error(), "token is revoked")
}).
When().
ListApplications("token2").
Then().
ActionShouldSucceed()
}
// TestLogoutRevokedTokenCannotAccessAPIs verifies that a revoked token is rejected
// across different API endpoints, not just GetUserInfo.
func TestLogoutRevokedTokenCannotAccessAPIs(t *testing.T) {
sessionFixture.Given(t).
When().
Login("token1").
GetUserInfo("token1").
Logout("token1").
GetUserInfo("token1").
ListAccounts("token1").
Then().
ActionShouldFail(func(err error) {
require.Contains(t, err.Error(), "token is revoked")
}).
// Project API
When().
ListProjects("token1").
Then().
ActionShouldFail(func(err error) {
require.Contains(t, err.Error(), "token is revoked")
}).
// Repository API
When().
ListRepositories("token1").
Then().
ActionShouldFail(func(err error) {
require.Contains(t, err.Error(), "token is revoked")
}).
// Application API
When().
ListApplications("token1").
Then().
ActionShouldFail(func(err error) {
require.Contains(t, err.Error(), "token is revoked")
})
}
// TestLogoutRevokesOIDCToken verifies that token revocation works for tokens
// issued directly by an external OIDC provider (bypassing Dex). This exercises
// the IDP token verification and revocation code path in SessionManager.VerifyToken.
func TestLogoutRevokesOIDCToken(t *testing.T) {
sessionFixture.Given(t).
When().
WithDirectOIDC().
LoginWithSSO("token1").
ListApplications("token1").
Then().
ActionShouldSucceed().
When().
Logout("token1").
ListApplications("token1").
Then().
ActionShouldFail(func(err error) {
require.Contains(t, err.Error(), "token is revoked")
})
}
// TestLogoutDoesNotAffectOtherOIDCSessions verifies that revoking one OIDC session
// token does not invalidate a different OIDC session token.
func TestLogoutDoesNotAffectOtherOIDCSessions(t *testing.T) {
sessionFixture.Given(t).
When().
WithDirectOIDC().
LoginWithSSO("token1").
LoginWithSSO("token2").
ListApplications("token1").
Then().
ActionShouldSucceed().
When().
Logout("token1").
ListApplications("token1").
Then().
ActionShouldFail(func(err error) {
require.Contains(t, err.Error(), "token is revoked")
}).
When().
ListApplications("token2").
Then().
ActionShouldSucceed()
}
// TestLogoutRevokedOIDCTokenCannotAccessAPIs verifies that a revoked OIDC token
// is rejected across different API endpoints.
func TestLogoutRevokedOIDCTokenCannotAccessAPIs(t *testing.T) {
sessionFixture.Given(t).
When().
WithDirectOIDC().
LoginWithSSO("token1").
GetUserInfo("token1").
Logout("token1").
GetUserInfo("token1").
ListApplications("token1").
Then().
ActionShouldFail(func(err error) {
require.Contains(t, err.Error(), "token is revoked")
}).
// Project API
When().
ListProjects("token1").
Then().
ActionShouldFail(func(err error) {
require.Contains(t, err.Error(), "token is revoked")
}).
// Repository API
When().
ListRepositories("token1").
Then().
ActionShouldFail(func(err error) {
require.Contains(t, err.Error(), "token is revoked")
})
}