Skip to content
Merged
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
51 changes: 50 additions & 1 deletion queueprovider/nats/export_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package nats

import "sync"
import (
"sync"
"time"

"github.com/nats-io/nkeys"
)

// PurgeAccountCacheForTest empties the in-memory accountCache. Used by tests
// to simulate the post-restart scenario where the cache is empty and the only
Expand All @@ -9,3 +14,47 @@ import "sync"
func (p *Provider) PurgeAccountCacheForTest() {
p.accountCache = sync.Map{}
}

// PoisonAccountCacheForTest stuffs a fake cachedAccount under the supplied
// resource token. Used to exercise the lookupCachedByPub "no-match-keep-
// scanning" branch with multiple entries in the cache.
func (p *Provider) PoisonAccountCacheForTest(token string) {
p.accountCache.Store(token, cachedAccount{
accountKP: nil,
accountPub: "AOTHER_PUB_KEY_THAT_NEVER_MATCHES",
accountJWT: "",
createdAt: time.Now(),
})
}

// SetCreateAccountKPForTest swaps the package-level account-NKey constructor.
// Returns a restore func. Lets tests drive the error branches that
// nkeys.CreateAccount otherwise never trips.
func SetCreateAccountKPForTest(fn func() (nkeys.KeyPair, error)) (restore func()) {
orig := createAccountKP
createAccountKP = fn
return func() { createAccountKP = orig }
}

// SetCreateUserKPForTest is the user-NKey-constructor counterpart.
func SetCreateUserKPForTest(fn func() (nkeys.KeyPair, error)) (restore func()) {
orig := createUserKP
createUserKP = fn
return func() { createUserKP = orig }
}

// SetFormatUserCredsForTest swaps the jwt.FormatUserConfig hook.
func SetFormatUserCredsForTest(fn func(string, []byte) ([]byte, error)) (restore func()) {
orig := formatUserCreds
formatUserCreds = fn
return func() { formatUserCreds = orig }
}

// SetParseOperatorKPForTest swaps the nkeys.FromSeed hook used by both
// builder() (to parse the operator seed) and RevokeWithSeed (to parse the
// per-tenant account seed).
func SetParseOperatorKPForTest(fn func([]byte) (nkeys.KeyPair, error)) (restore func()) {
orig := parseOperatorKP
parseOperatorKP = fn
return func() { parseOperatorKP = orig }
}
21 changes: 16 additions & 5 deletions queueprovider/nats/nats.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,17 @@ func init() {
queueprovider.Register("nats", builder)
}

// Test seams. These are package-level vars so unit tests can substitute
// failing implementations and exercise the error branches that the real
// nkeys/jwt libraries practically never hit. In production they alias the
// upstream constructors 1:1.
var (
createAccountKP = nkeys.CreateAccount
createUserKP = nkeys.CreateUser
formatUserCreds = jwt.FormatUserConfig
parseOperatorKP = nkeys.FromSeed
)

// builder is the Factory entry point. Returns ErrAuthFailure-flavored errors
// when the operator seed is unparseable, so the caller can degrade gracefully
// during the pre-cutover window.
Expand Down Expand Up @@ -96,7 +107,7 @@ func builder(cfg queueprovider.Config) (queueprovider.QueueCredentialProvider, e
// understands operator mode first, populate the secret + flip
// nats.yaml later.
if cfg.NATSOperatorSeed != "" {
opKP, err := nkeys.FromSeed([]byte(cfg.NATSOperatorSeed))
opKP, err := parseOperatorKP([]byte(cfg.NATSOperatorSeed))
if err != nil {
return nil, fmt.Errorf("%w: parse operator seed: %v", queueprovider.ErrAuthFailure, err)
}
Expand Down Expand Up @@ -220,7 +231,7 @@ func (p *Provider) IssueTenantCredentials(ctx context.Context, in queueprovider.
}

// 1. Mint account NKey pair.
accountKP, err := nkeys.CreateAccount()
accountKP, err := createAccountKP()
if err != nil {
return nil, fmt.Errorf("queueprovider.nats: create account NKey: %w", err)
}
Expand Down Expand Up @@ -272,7 +283,7 @@ func (p *Provider) IssueTenantCredentials(ctx context.Context, in queueprovider.
})

// 4. Mint user NKey pair + sign user JWT with the account seed.
userKP, err := nkeys.CreateUser()
userKP, err := createUserKP()
if err != nil {
return nil, fmt.Errorf("queueprovider.nats: create user NKey: %w", err)
}
Expand Down Expand Up @@ -316,7 +327,7 @@ func (p *Provider) IssueTenantCredentials(ctx context.Context, in queueprovider.
return nil, fmt.Errorf("queueprovider.nats: sign user JWT: %w", err)
}

credsFile, err := jwt.FormatUserConfig(userJWT, userSeed)
credsFile, err := formatUserCreds(userJWT, userSeed)
if err != nil {
return nil, fmt.Errorf("queueprovider.nats: format .creds blob: %w", err)
}
Expand Down Expand Up @@ -397,7 +408,7 @@ func (p *Provider) RevokeWithSeed(ctx context.Context, accountSeed string) error
if !p.operatorReady || accountSeed == "" {
return nil
}
kp, err := nkeys.FromSeed([]byte(accountSeed))
kp, err := parseOperatorKP([]byte(accountSeed))
if err != nil {
return fmt.Errorf("queueprovider.nats: parse account seed: %w", err)
}
Expand Down
Loading
Loading