From 60df958474cd877fa6648b1a3c455c1eedba2935 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 4 Apr 2026 12:37:51 +0000 Subject: [PATCH] refactor(auth): move generateRandomAPIKey to internal/auth package The function is about API key generation for authentication purposes, making internal/auth the natural home. Export it as GenerateRandomAPIKey so cmd/root.go can call it via the auth package interface. - Add internal/auth/apikey.go with GenerateRandomAPIKey() - Add internal/auth/apikey_test.go (moved from cmd/root_test.go) - Update cmd/root.go: add auth import, remove crypto/rand & encoding/hex - Remove TestGenerateRandomAPIKey from cmd/root_test.go (moved to auth) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- internal/auth/apikey.go | 18 ++++++++++++++++++ internal/auth/apikey_test.go | 24 ++++++++++++++++++++++++ internal/cmd/root.go | 16 ++-------------- internal/cmd/root_test.go | 15 --------------- 4 files changed, 44 insertions(+), 29 deletions(-) create mode 100644 internal/auth/apikey.go create mode 100644 internal/auth/apikey_test.go diff --git a/internal/auth/apikey.go b/internal/auth/apikey.go new file mode 100644 index 00000000..031ea597 --- /dev/null +++ b/internal/auth/apikey.go @@ -0,0 +1,18 @@ +package auth + +import ( + "crypto/rand" + "encoding/hex" + "fmt" +) + +// GenerateRandomAPIKey generates a cryptographically random API key. +// Per spec §7.3, the gateway SHOULD generate a random API key on startup +// if none is provided. Returns a 32-byte hex-encoded string (64 chars). +func GenerateRandomAPIKey() (string, error) { + bytes := make([]byte, 32) + if _, err := rand.Read(bytes); err != nil { + return "", fmt.Errorf("failed to generate random API key: %w", err) + } + return hex.EncodeToString(bytes), nil +} diff --git a/internal/auth/apikey_test.go b/internal/auth/apikey_test.go new file mode 100644 index 00000000..0f10dca1 --- /dev/null +++ b/internal/auth/apikey_test.go @@ -0,0 +1,24 @@ +package auth_test + +import ( + "testing" + + "github.com/github/gh-aw-mcpg/internal/auth" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// TestGenerateRandomAPIKey verifies that GenerateRandomAPIKey produces a +// non-empty, unique, hex-encoded string per spec §7.3. +func TestGenerateRandomAPIKey(t *testing.T) { + key, err := auth.GenerateRandomAPIKey() + require.NoError(t, err, "GenerateRandomAPIKey() should not fail") + assert.NotEmpty(t, key, "generated key should not be empty") + // 32 bytes encoded as hex = 64 characters + assert.Len(t, key, 64, "generated key should be 64 hex characters") + + // Verify keys are unique across calls + key2, err := auth.GenerateRandomAPIKey() + require.NoError(t, err) + assert.NotEqual(t, key, key2, "successive calls should produce unique keys") +} diff --git a/internal/cmd/root.go b/internal/cmd/root.go index 3db309b2..4348a8c6 100644 --- a/internal/cmd/root.go +++ b/internal/cmd/root.go @@ -3,8 +3,6 @@ package cmd import ( "bufio" "context" - "crypto/rand" - "encoding/hex" "encoding/json" "fmt" "io" @@ -17,6 +15,7 @@ import ( "syscall" "time" + "github.com/github/gh-aw-mcpg/internal/auth" "github.com/github/gh-aw-mcpg/internal/config" "github.com/github/gh-aw-mcpg/internal/difc" "github.com/github/gh-aw-mcpg/internal/logger" @@ -303,7 +302,7 @@ func run(cmd *cobra.Command, args []string) error { // The generated key is set in the config so it propagates to both the HTTP // server authentication and the stdout configuration output (spec §5.4). if cfg.GetAPIKey() == "" { - randomKey, err := generateRandomAPIKey() + randomKey, err := auth.GenerateRandomAPIKey() if err != nil { return fmt.Errorf("failed to generate random API key: %w", err) } @@ -587,17 +586,6 @@ func loadEnvFile(path string) error { return scanner.Err() } -// generateRandomAPIKey generates a cryptographically random API key. -// Per spec §7.3, the gateway SHOULD generate a random API key on startup -// if none is provided. Returns a 32-byte hex-encoded string (64 chars). -func generateRandomAPIKey() (string, error) { - bytes := make([]byte, 32) - if _, err := rand.Read(bytes); err != nil { - return "", fmt.Errorf("failed to generate random API key: %w", err) - } - return hex.EncodeToString(bytes), nil -} - // Execute runs the root command func Execute() { if err := rootCmd.Execute(); err != nil { diff --git a/internal/cmd/root_test.go b/internal/cmd/root_test.go index 64e96a0d..966153b2 100644 --- a/internal/cmd/root_test.go +++ b/internal/cmd/root_test.go @@ -508,18 +508,3 @@ func TestPostRunCleanup(t *testing.T) { assert.NotNil(t, rootCmd.PersistentPostRun, "PersistentPostRun should be set") }) } - -// TestGenerateRandomAPIKey verifies that generateRandomAPIKey produces a -// non-empty, unique, hex-encoded string per spec §7.3. -func TestGenerateRandomAPIKey(t *testing.T) { - key, err := generateRandomAPIKey() - require.NoError(t, err, "generateRandomAPIKey() should not fail") - assert.NotEmpty(t, key, "generated key should not be empty") - // 32 bytes encoded as hex = 64 characters - assert.Len(t, key, 64, "generated key should be 64 hex characters") - - // Verify keys are unique across calls - key2, err := generateRandomAPIKey() - require.NoError(t, err) - assert.NotEqual(t, key, key2, "successive calls should produce unique keys") -}