Repository: jkroepke/openvpn-auth-oauth2
Pull request #558 (2025-07-19 20:57:32)

chore: test coverage
#### What this PR does / why we need it

#### Which issue this PR fixes

*(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close that issue when PR gets merged)*: fixes #

- fixes #

#### Special notes for your reviewer

#### Particularly user-facing changes

#### Checklist

Complete these before marking the PR as `ready to review`:

<!-- [Place an '[x]' (no spaces) in all applicable fields.] -->

- [ ] [DCO](https://github.com/prometheus-community/helm-charts/blob/main/CONTRIBUTING.md#sign-off-your-work) signed
- [ ] The PR title has a summary of the changes
- [ ] The PR body has a summary to reflect any significant (and particularly user-facing) changes introduced by this PR



Patch:
diff --git a/cmd/daemon/root.go b/cmd/daemon/root.go
index 794b576..d8f558d 100644
--- a/cmd/daemon/root.go
+++ b/cmd/daemon/root.go
@@ -160,10 +160,13 @@ func setupOpenVPNClient(
 ) (*openvpn.Client, *http.ServeMux, error) {
 	httpClient := &http.Client{Transport: utils.NewUserAgentTransport(http.DefaultTransport)}
 	tokenStorage := tokenstorage.NewInMemory(conf.OAuth2.Refresh.Secret.String(), conf.OAuth2.Refresh.Expires)
-	tokenStorage.SetStorage(tokenDataStorage)
+
+	err := tokenStorage.SetStorage(tokenDataStorage)
+	if err != nil {
+		return nil, nil, fmt.Errorf("error setting token storage: %w", err)
+	}
 
 	var (
-		err      error
 		provider oauth2.Provider
 	)
 
diff --git a/internal/tokenstorage/inmemory.go b/internal/tokenstorage/inmemory.go
index 9585a8e..6e1e0fc 100644
--- a/internal/tokenstorage/inmemory.go
+++ b/internal/tokenstorage/inmemory.go
@@ -9,6 +9,8 @@ import (
 	"github.com/zitadel/oidc/v3/pkg/crypto"
 )
 
+var ErrNilData = errors.New("data map cannot be nil")
+
 // InMemory provides an in-memory implementation of a token storage system.
 // It stores encrypted tokens associated with clients, supports expiration, and is safe for concurrent use.
 type InMemory struct {
@@ -33,12 +35,20 @@ func NewInMemory(encryptionKey string, expires time.Duration) *InMemory {
 
 // SetStorage replaces the current storage data with the provided DataMap.
 // This is mainly used for testing or restoring state.
-func (s *InMemory) SetStorage(data DataMap) {
+func (s *InMemory) SetStorage(data DataMap) error {
 	s.mu.Lock()
 
+	if data == nil {
+		s.mu.Unlock()
+
+		return ErrNilData
+	}
+
 	s.data = data
 
 	s.mu.Unlock()
+
+	return nil
 }
 
 // Set stores an encrypted token for a given client, with an expiration time.
@@ -68,12 +78,6 @@ func (s *InMemory) Set(client, token string) error {
 func (s *InMemory) Get(client string) (string, error) {
 	s.mu.RLock()
 
-	if s.data == nil {
-		s.mu.RUnlock()
-
-		return "", ErrNotExists
-	}
-
 	data, ok := s.data[client]
 	if !ok {
 		s.mu.RUnlock()
@@ -106,12 +110,6 @@ func (s *InMemory) Get(client string) (string, error) {
 func (s *InMemory) Delete(client string) error {
 	s.mu.Lock()
 
-	if s.data == nil {
-		s.mu.Unlock()
-
-		return nil
-	}
-
 	delete(s.data, client)
 
 	s.mu.Unlock()


Test patch:
diff --git a/internal/config/validate_test.go b/internal/config/validate_test.go
index 3910a01..ef190a8 100644
--- a/internal/config/validate_test.go
+++ b/internal/config/validate_test.go
@@ -3,6 +3,7 @@ package config_test
 import (
 	"net/url"
 	"testing"
+	"text/template"
 
 	"github.com/jkroepke/openvpn-auth-oauth2/internal/config"
 	"github.com/jkroepke/openvpn-auth-oauth2/internal/config/types"
@@ -67,6 +68,23 @@ func TestValidate(t *testing.T) {
 			},
 			"http.baseurl is required",
 		},
+		{
+			config.Config{
+				HTTP: config.HTTP{
+					BaseURL:  types.URL{URL: &url.URL{Scheme: "http", Host: "localhost"}},
+					Secret:   testutils.Secret,
+					Template: types.Template{Template: template.Must(template.New("index.gohtml").Parse("{{ slice .invalid.error 1 2 }}"))},
+				},
+				OAuth2: config.OAuth2{
+					Client: config.OAuth2Client{ID: "ID", Secret: testutils.Secret},
+					Issuer: types.URL{URL: &url.URL{Scheme: "http", Host: "localhost"}},
+				},
+				OpenVPN: config.OpenVPN{
+					Addr: types.URL{URL: &url.URL{Scheme: "tcp", Host: "127.0.0.1:9000"}},
+				},
+			},
+			"invalid rendering http.template: template: index.gohtml:1:3: executing \"index.gohtml\" at <slice .invalid.error 1 2>: error calling slice: slice of untyped nil",
+		},
 		{
 			config.Config{
 				HTTP: config.HTTP{
diff --git a/internal/tokenstorage/inmemory_test.go b/internal/tokenstorage/inmemory_test.go
index 7db3dfe..46e0754 100644
--- a/internal/tokenstorage/inmemory_test.go
+++ b/internal/tokenstorage/inmemory_test.go
@@ -1,6 +1,7 @@
 package tokenstorage_test
 
 import (
+	"crypto/aes"
 	"testing"
 	"time"
 
@@ -10,7 +11,7 @@ import (
 	"github.com/stretchr/testify/require"
 )
 
-func TestStorage_InMemory(t *testing.T) {
+func TestStorageInMemory(t *testing.T) {
 	t.Parallel()
 
 	tokenStorage := tokenstorage.NewInMemory(testutils.Secret, time.Millisecond*400)
@@ -48,7 +49,7 @@ func TestStorage_InMemory(t *testing.T) {
 	require.ErrorIs(t, err, tokenstorage.ErrNotExists)
 }
 
-func TestStorageExpire_InMemory(t *testing.T) {
+func TestStorageInMemory_Expire(t *testing.T) {
 	t.Parallel()
 
 	tokenStorage := tokenstorage.NewInMemory(testutils.Secret, 0)
@@ -66,3 +67,25 @@ func TestStorageExpire_InMemory(t *testing.T) {
 	_, err = tokenStorage.Get("1")
 	require.ErrorIs(t, err, tokenstorage.ErrNotExists)
 }
+
+func TestStorageInMemory_InvalidSecret(t *testing.T) {
+	t.Parallel()
+
+	key := "invalid"
+
+	tokenStorage := tokenstorage.NewInMemory(key, 0)
+
+	t.Cleanup(func() {
+		require.NoError(t, tokenStorage.Close())
+	})
+
+	require.ErrorIs(t, tokenStorage.Set("0", "TEST0"), aes.KeySizeError(len(key)))
+}
+
+func TestStorageInMemory_InvalidData(t *testing.T) {
+	t.Parallel()
+
+	tokenStorage := tokenstorage.NewInMemory(testutils.Secret, 0)
+
+	require.ErrorIs(t, tokenStorage.SetStorage(nil), tokenstorage.ErrNilData)
+}