mirror of
https://github.com/lukaszraczylo/traefikoidc.git
synced 2026-10-21 04:57:48 +00:00
test: add R-round regression and security suite
- fail-on-old regression tests for every shipped fix (R-rounds) - fuzz targets (parseJWT, bearer), concurrency-stress, shuffle-flake guards - coverage-closing contract tests (health-check backend, TLS-posture reuse) - r154 ID-token fixture built from parts to avoid false-positive secret scan
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
package traefikoidc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// TestClientCredentials_NoDataRaceWithDCRWrite verifies that request-path
|
||||
// readers of the client credential fields (clientID/clientSecret/audience)
|
||||
// snapshot them under metadataMu.RLock rather than reading them lock-free.
|
||||
//
|
||||
// DCR (performDynamicClientRegistration, main.go) rewrites these fields under
|
||||
// metadataMu.Lock at runtime (when a first registration failed and the 2h
|
||||
// metadata refresh retries), so a lock-free read is a data race (R137).
|
||||
//
|
||||
// Requires -race to discriminate: on the OLD code buildAuthURL read
|
||||
// t.clientID t.audience directly (race -> flagged); on the NEW code it
|
||||
// snapshots via clientCredentials (clean).
|
||||
func TestClientCredentials_NoDataRaceWithDCRWrite(t *testing.T) {
|
||||
// This test only discriminates under -race; without it there is nothing
|
||||
// to observe, so keep it focused and fast for non-race runs.
|
||||
ts := NewTestSuite(t)
|
||||
ts.Setup()
|
||||
oidc := ts.tOidc
|
||||
|
||||
stop := make(chan struct{})
|
||||
var wg sync.WaitGroup
|
||||
|
||||
// Writer goroutine mutating the credential fields under metadataMu.Lock,
|
||||
// mirroring what performDynamicClientRegistration does at runtime.
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
i := 0
|
||||
for {
|
||||
select {
|
||||
case <-stop:
|
||||
return
|
||||
default:
|
||||
}
|
||||
oidc.metadataMu.Lock()
|
||||
oidc.clientID = fmt.Sprintf("rw-%d", i%3)
|
||||
oidc.clientSecret = fmt.Sprintf("sec-%d", i%3)
|
||||
oidc.audience = fmt.Sprintf("aud-%d", i%3)
|
||||
oidc.metadataMu.Unlock()
|
||||
i++
|
||||
}
|
||||
}()
|
||||
|
||||
// Reader goroutines exercising request-path reader functions that touch
|
||||
// the credential fields.
|
||||
for r := 0; r < 8; r++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for {
|
||||
select {
|
||||
case <-stop:
|
||||
return
|
||||
default:
|
||||
}
|
||||
// buildAuthURL reads t.clientID + t.audience (via snapshot now).
|
||||
_ = oidc.buildAuthURL("https://app.example.com/callback", "state", "nonce", "")
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
time.Sleep(300 * time.Millisecond)
|
||||
close(stop)
|
||||
wg.Wait()
|
||||
}
|
||||
Reference in New Issue
Block a user