Skip to content

chore(coderd/coderdtest/oidctest): protect mutable fields with rwmutex #17151

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 6 commits into from
Apr 2, 2025

Conversation

johnstcn
Copy link
Member

Fixes a test flake seen here: https://github.com/coder/coder/actions/runs/14129446248/job/39585915325

WARNING: DATA RACE
Write at 0x00c0174f5918 by goroutine 11046:
  github.com/coder/coder/v2/coderd/coderdtest/oidctest.(*FakeIDP).SetRedirect()
      /home/runner/work/coder/coder/coderd/coderdtest/oidctest/idp.go:1280 +0x1e6
  github.com/coder/coder/v2/coderd/coderdtest/oidctest.(*FakeIDP).LoginWithClient()
      /home/runner/work/coder/coder/coderd/coderdtest/oidctest/idp.go:494 +0x170
  github.com/coder/coder/v2/coderd/coderdtest/oidctest.(*FakeIDP).AttemptLogin()
      /home/runner/work/coder/coder/coderd/coderdtest/oidctest/idp.go:[479](https://github.com/coder/coder/actions/runs/14129446248/job/39585915325#step:7:480) +0x624
  github.com/coder/coder/v2/coderd_test.TestOIDCDomainErrorMessage.func2()
      /home/runner/work/coder/coder/coderd/userauth_test.go:2014 +0x1f2
  testing.tRunner()
      /opt/hostedtoolcache/go/1.24.1/x64/src/testing/testing.go:1792 +0x225
  testing.(*T).Run.gowrap1()
      /opt/hostedtoolcache/go/1.24.1/x64/src/testing/testing.go:1851 +0x44

Previous read at 0x00c0174f5918 by goroutine 104380:
  golang.org/x/oauth2.(*Config).Exchange()
      /home/runner/go/pkg/mod/golang.org/x/oauth2@v0.28.0/oauth2.go:228 +0x1d8
  github.com/coder/coder/v2/coderd.(*OIDCConfig).Exchange()
      <autogenerated>:1 +0xb7
  github.com/coder/coder/v2/coderd.New.func11.12.1.2.ExtractOAuth2.1.1()
      /home/runner/work/coder/coder/coderd/httpmw/oauth2.go:168 +0x7b5
  net/http.HandlerFunc.ServeHTTP()
      /opt/hostedtoolcache/go/1.24.1/x64/src/net/http/server.go:2294 +0x47
  github.com/go-chi/chi/v5.(*Mux).ServeHTTP()
      /home/runner/go/pkg/mod/github.com/go-chi/chi/v5@v5.1.0/mux.go:73 +0x6f6
  github.com/go-chi/chi/v5.(*Mux).Mount.func1()
      /home/runner/go/pkg/mod/github.com/go-chi/chi/v5@v5.1.0/mux.go:327 +0x4bd
  net/http.HandlerFunc.ServeHTTP()
      /opt/hostedtoolcache/go/1.24.1/x64/src/net/http/server.go:2294 +0x47
[...]

@johnstcn johnstcn self-assigned this Mar 28, 2025
@johnstcn johnstcn requested review from Emyrk and mafredri March 28, 2025 14:01
Copy link
Member

@mafredri mafredri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for working on this!

@johnstcn
Copy link
Member Author

OK, I changed this around a little bit a lot. I'm now protecting a lot more stuff inside a separate struct.

@@ -110,8 +203,8 @@ type FakeIDP struct {
// some claims.
defaultIDClaims jwt.MapClaims
hookMutateToken func(token map[string]interface{})
fakeCoderd func(req *http.Request) (*http.Response, error)
hookOnRefresh func(email string) error
// fakeCoderd func(req *http.Request) (*http.Response, error)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved to protected

Suggested change
// fakeCoderd func(req *http.Request) (*http.Response, error)

Copy link
Member

@mafredri mafredri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few caveats, but probably don't need to re-review.

provider ProviderJSON
handler http.Handler
cfg *oauth2.Config
prot fakeIDPProtected
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Maybe rename to priv/private, internal, etc? Prot makes me think of protoc/prototypes.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed to locked. 👍

if cfg == nil {
cfg = &oauth2.Config{}
}
fn(cfg)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: This mutates the config which is a pointer, meaning the mutex only protects f.cfg but not the actual &oauth2.Config{} which could be modified and read in a racy way? I'd suggest at least making a copy of it, but did not verify if that's sufficient.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we take your suggestion above then we can just mutate f.cfg directly.

Copy link
Member

@mafredri mafredri Apr 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're worried about races and re-entrant locking, couldn't we just do this?

	f.mu.Lock()
	if f.cfg == nil {
		f.cfg = &oauth2.Config{}
	}
	cfg := *f.cfg
	f.mu.Unlock()
	fn(cfg)
	f.mu.Lock()
	f.cfg = &cfg
	f.mu.Unlock()

Copy link
Member Author

@johnstcn johnstcn Apr 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I make a shallow copy of f.cfg it causes TestOIDCSkipIssuer to fail, most likely due to some missing unexported fields. We may sadly have to live with the possibility of re-entrant locks.

@johnstcn johnstcn merged commit 8cecc4f into main Apr 2, 2025
33 of 34 checks passed
@johnstcn johnstcn deleted the cj/flake/TestOIDCDomainErrorMessage branch April 2, 2025 12:36
@github-actions github-actions bot locked and limited conversation to collaborators Apr 2, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants