Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -109,4 +109,4 @@ replace github.com/prometheus/golang_client => github.com/prometheus/golang_clie
replace gopkg.in/yaml.v3 => gopkg.in/yaml.v3 v3.0.1

// This fork is based on quic-go v0.45
replace github.com/quic-go/quic-go => github.com/chungthuang/quic-go v0.45.1-0.20250428085412-43229ad201fd
replace github.com/quic-go/quic-go => github.com/stareezy-1/quic-go v0.0.0-20260806091559-d3ee2305a943
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ github.com/bytedance/sonic/loader v0.2.0 h1:zNprn+lsIP06C/IqCHs3gPQIvnvpKbbxyXQP
github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chungthuang/quic-go v0.45.1-0.20250428085412-43229ad201fd h1:VdYI5zFQ2h1/qzoC6rhyPx479bkF8i177Qpg4Q2n1vk=
github.com/chungthuang/quic-go v0.45.1-0.20250428085412-43229ad201fd/go.mod h1:MFlGGpcpJqRAfmYi6NC2cptDPSxRWTOGNuP4wqrWmzQ=
github.com/cloudflare/backoff v0.0.0-20240920015135-e46b80a3a7d0 h1:pRcxfaAlK0vR6nOeQs7eAEvjJzdGXl8+KaBlcvpQTyQ=
github.com/cloudflare/backoff v0.0.0-20240920015135-e46b80a3a7d0/go.mod h1:rzgs2ZOiguV6/NpiDgADjRLPNyZlApIWxKpkT+X8SdY=
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
Expand Down Expand Up @@ -189,6 +187,8 @@ github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD
github.com/shirou/gopsutil/v4 v4.26.3 h1:2ESdQt90yU3oXF/CdOlRCJxrP+Am1aBYubTMTfxJ1qc=
github.com/shirou/gopsutil/v4 v4.26.3/go.mod h1:LZ6ewCSkBqUpvSOf+LsTGnRinC6iaNUNMGBtDkJBaLQ=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/stareezy-1/quic-go v0.0.0-20260806091559-d3ee2305a943 h1:67fF8SB/JinU0QavrnZ8I3+J6GMtK2b1I2IMQfUdF3U=
github.com/stareezy-1/quic-go v0.0.0-20260806091559-d3ee2305a943/go.mod h1:MFlGGpcpJqRAfmYi6NC2cptDPSxRWTOGNuP4wqrWmzQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
Expand Down
33 changes: 33 additions & 0 deletions token/lockfile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"path/filepath"
"testing"

"github.com/rs/zerolog"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
Expand Down Expand Up @@ -112,3 +113,35 @@ func TestNewSelfLockContent(t *testing.T) {
assert.Equal(t, int32(os.Getpid()), content.PID) // nolint: gosec
assert.Positive(t, content.StartTime)
}

func TestReleaseLockFileAllowsReacquire(t *testing.T) {
// Regression test for the `access login` self-deadlock (issue #1692):
// the token lock was held for the whole process lifetime, so a second
// fetch in the same process (after an invalid token was removed) waited
// forever on its own lock. After release, the same process can acquire
// the lock again.
log := zerolog.Nop()
path := filepath.Join(t.TempDir(), "token")

require.NoError(t, acquireLockFile(path, &log))
releaseLockFile(path, &log)
require.NoError(t, acquireLockFile(path, &log), "must be able to re-acquire after release")
releaseLockFile(path, &log)
}

func TestReleaseLockFileDoesNotRemoveOtherProcessLock(t *testing.T) {
// Releasing must not remove a lock owned by another process.
log := zerolog.Nop()
dir := t.TempDir()
path := filepath.Join(dir, "token")
lockPath := path + ".lock"

other := lockContent{PID: 2147483647, StartTime: 1000000000000}
data, err := json.Marshal(other)
require.NoError(t, err)
require.NoError(t, os.WriteFile(lockPath, data, 0600))

releaseLockFile(path, &log)
_, err = os.Stat(lockPath)
require.NoError(t, err, "another process's lock must not be removed")
}
31 changes: 31 additions & 0 deletions token/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,32 @@ func acquireLockFile(tokenPath string, log *zerolog.Logger) error {
}
}

// releaseLockFile removes the lock file for the given token path if it is
// still owned by this process. Locks are held for the duration of a single
// token acquisition; releasing them lets a later re-fetch in the same
// process (e.g. after an invalid token was removed by the caller) acquire
// the lock again instead of deadlocking on its own lock.
func releaseLockFile(tokenPath string, log *zerolog.Logger) {
lockPath := tokenPath + ".lock"
_, content, err := isLockFileStale(lockPath)
if err != nil {
return
}
self, err := newSelfLockContent()
if err != nil {
return
}
if content.PID != self.PID || content.StartTime != self.StartTime {
// Another process reclaimed the lock; leave it alone.
return
}
if err := os.Remove(lockPath); err != nil && !os.IsNotExist(err) {
log.Debug().Err(err).Str("path", lockPath).Msg("failed to release lock file")
return
}
log.Debug().Str("path", lockPath).Msg("lock file released")
}

// readAuthURL reads the auth URL companion file for the given token path.
// Returns the URL string, or empty string if the file doesn't exist or
// can't be read.
Expand Down Expand Up @@ -290,6 +316,10 @@ func getToken(appURL *url.URL, appInfo *AppInfo, useHostOnly bool, autoClose boo
if err = acquireLockFile(appTokenPath, log); err != nil {
return "", errors.Wrap(err, "failed to acquire app token lock")
}
// Release the lock when this fetch completes: holding it for the whole
// process lifetime makes a same-process re-fetch (after an invalid token
// was removed) deadlock on its own lock (issue #1692).
defer releaseLockFile(appTokenPath, log)

// check to see if another process has gotten a token while we waited for the lock
if token, err := GetAppTokenIfExists(appInfo); token != "" && err == nil {
Expand All @@ -308,6 +338,7 @@ func getToken(appURL *url.URL, appInfo *AppInfo, useHostOnly bool, autoClose boo
if err = acquireLockFile(orgTokenPath, log); err != nil {
return "", errors.Wrap(err, "failed to acquire org token lock")
}
defer releaseLockFile(orgTokenPath, log)
// check if an org token has been created since the lock was acquired
orgToken, err = GetOrgTokenIfExists(appInfo.AuthDomain)
}
Expand Down
7 changes: 7 additions & 0 deletions vendor/github.com/quic-go/quic-go/connection.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions vendor/modules.txt
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ github.com/prometheus/common/model
github.com/prometheus/procfs
github.com/prometheus/procfs/internal/fs
github.com/prometheus/procfs/internal/util
# github.com/quic-go/quic-go v0.52.0 => github.com/chungthuang/quic-go v0.45.1-0.20250428085412-43229ad201fd
# github.com/quic-go/quic-go v0.52.0 => github.com/stareezy-1/quic-go v0.0.0-20260806091559-d3ee2305a943
## explicit; go 1.23
github.com/quic-go/quic-go
github.com/quic-go/quic-go/internal/ackhandler
Expand Down Expand Up @@ -571,4 +571,4 @@ zombiezen.com/go/capnproto2/std/capnp/rpc
# github.com/urfave/cli/v2 => github.com/ipostelnik/cli/v2 v2.3.1-0.20210324024421-b6ea8234fe3d
# github.com/prometheus/golang_client => github.com/prometheus/golang_client v1.12.1
# gopkg.in/yaml.v3 => gopkg.in/yaml.v3 v3.0.1
# github.com/quic-go/quic-go => github.com/chungthuang/quic-go v0.45.1-0.20250428085412-43229ad201fd
# github.com/quic-go/quic-go => github.com/stareezy-1/quic-go v0.0.0-20260806091559-d3ee2305a943