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
38 changes: 19 additions & 19 deletions internal/auth/apikey_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,62 +10,62 @@ import (
"github.com/stretchr/testify/require"
)

// TestGenerateRandomAPIKey verifies that GenerateRandomAPIKey produces a
// TestGenerateRandomAgentID verifies that GenerateRandomAgentID 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")
func TestGenerateRandomAgentID(t *testing.T) {
key, err := auth.GenerateRandomAgentID()
require.NoError(t, err, "GenerateRandomAgentID() 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()
key2, err := auth.GenerateRandomAgentID()
require.NoError(t, err)
assert.NotEqual(t, key, key2, "successive calls should produce unique keys")
}

// TestGenerateRandomAPIKey_IsValidHex verifies the returned key is a valid
// TestGenerateRandomAgentID_IsValidHex verifies the returned key is a valid
// hex-encoded string that decodes to exactly 32 bytes.
func TestGenerateRandomAPIKey_IsValidHex(t *testing.T) {
key, err := auth.GenerateRandomAPIKey()
func TestGenerateRandomAgentID_IsValidHex(t *testing.T) {
key, err := auth.GenerateRandomAgentID()
require.NoError(t, err)

decoded, decodeErr := hex.DecodeString(key)
require.NoError(t, decodeErr, "key should be valid hex-encoded string; got %q", key)
assert.Len(t, decoded, 32, "decoded key should be 32 bytes")
}

// TestGenerateRandomAPIKey_IsLowercaseHex verifies the key uses only lowercase
// TestGenerateRandomAgentID_IsLowercaseHex verifies the key uses only lowercase
// hex characters (0-9, a-f) as produced by hex.EncodeToString.
func TestGenerateRandomAPIKey_IsLowercaseHex(t *testing.T) {
key, err := auth.GenerateRandomAPIKey()
func TestGenerateRandomAgentID_IsLowercaseHex(t *testing.T) {
key, err := auth.GenerateRandomAgentID()
require.NoError(t, err)

matched, matchErr := regexp.MatchString(`^[0-9a-f]{64}$`, key)
require.NoError(t, matchErr)
assert.True(t, matched, "key should consist of exactly 64 lowercase hex chars; got %q", key)
}

// TestGenerateRandomAPIKey_Uniqueness verifies that repeated calls produce
// TestGenerateRandomAgentID_Uniqueness verifies that repeated calls produce
// distinct keys, confirming that crypto/rand entropy is used.
func TestGenerateRandomAPIKey_Uniqueness(t *testing.T) {
func TestGenerateRandomAgentID_Uniqueness(t *testing.T) {
const n = 20
seen := make(map[string]bool, n)
for i := 0; i < n; i++ {
key, err := auth.GenerateRandomAPIKey()
require.NoError(t, err, "call %d: GenerateRandomAPIKey() should not fail", i+1)
key, err := auth.GenerateRandomAgentID()
require.NoError(t, err, "call %d: GenerateRandomAgentID() should not fail", i+1)
assert.False(t, seen[key], "call %d: generated duplicate key %q", i+1, key)
seen[key] = true
}
}

// TestGenerateRandomAPIKey_LengthConsistency verifies that every call returns
// TestGenerateRandomAgentID_LengthConsistency verifies that every call returns
// a key of exactly 64 characters, regardless of call order.
func TestGenerateRandomAPIKey_LengthConsistency(t *testing.T) {
func TestGenerateRandomAgentID_LengthConsistency(t *testing.T) {
for i := 0; i < 10; i++ {
key, err := auth.GenerateRandomAPIKey()
require.NoError(t, err, "call %d: GenerateRandomAPIKey() should not fail", i+1)
key, err := auth.GenerateRandomAgentID()
require.NoError(t, err, "call %d: GenerateRandomAgentID() should not fail", i+1)
assert.Len(t, key, 64, "call %d: key should always be 64 characters", i+1)
}
}
11 changes: 3 additions & 8 deletions internal/auth/header.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,11 +119,6 @@ func ValidateAgentID(provided, expected string) bool {
return matches
}

// ValidateAPIKey is a deprecated alias for ValidateAgentID.
func ValidateAPIKey(provided, expected string) bool {
return ValidateAgentID(provided, expected)
}

// ExtractAgentID extracts the agent ID from an Authorization header.
// This is a convenience wrapper around ParseAuthHeader that only returns the agent ID.
// Returns "default" if the header is empty or cannot be parsed.
Expand Down Expand Up @@ -206,10 +201,10 @@ func IsMalformedHeader(header string) bool {
return false
}

// GenerateRandomAPIKey generates a cryptographically random API key.
// Per spec §7.3, the gateway SHOULD generate a random API key on startup
// GenerateRandomAgentID generates a cryptographically random agent ID.
// Per spec §7.3, the gateway SHOULD generate a random agent ID on startup
// if none is provided. Returns a 32-byte hex-encoded string (64 chars).
func GenerateRandomAPIKey() (string, error) {
func GenerateRandomAgentID() (string, error) {
logAPIKey.Print("Generating random agent ID")
key, err := strutil.RandomHex(32)
if err != nil {
Expand Down
5 changes: 0 additions & 5 deletions internal/auth/header_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -323,11 +323,6 @@ func TestValidateAgentID(t *testing.T) {
}
}

func TestValidateAPIKeyAlias(t *testing.T) {
assert.True(t, ValidateAPIKey("same", "same"))
assert.False(t, ValidateAPIKey("a", "b"))
}

func TestExtractAgentID(t *testing.T) {
assert := assert.New(t)

Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ func run(cmd *cobra.Command, args []string) error {
// The generated value is set in the config so it propagates to both the HTTP
// server authentication and the stdout configuration output (spec §5.4).
if cfg.GetAgentID() == "" {
randomKey, err := auth.GenerateRandomAPIKey()
randomKey, err := auth.GenerateRandomAgentID()
if err != nil {
return fmt.Errorf("failed to generate random agent ID: %w", err)
}
Expand Down
5 changes: 0 additions & 5 deletions internal/config/config_core.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,11 +182,6 @@ func (c *Config) GetAgentID() string {
return c.Gateway.effectiveAgentID()
}

// GetAPIKey is a deprecated alias for GetAgentID.
func (c *Config) GetAPIKey() string {
return c.GetAgentID()
}

func (g *GatewayConfig) effectiveAgentID() string {
if g == nil {
return ""
Expand Down
5 changes: 0 additions & 5 deletions internal/config/config_env.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,6 @@ func GetGatewayAgentIDFromEnv() string {
return ""
}

// GetGatewayAPIKeyFromEnv is a deprecated alias for GetGatewayAgentIDFromEnv.
func GetGatewayAPIKeyFromEnv() string {
return GetGatewayAgentIDFromEnv()
}

// GetGatewayToolTimeoutFromEnv returns the MCP_GATEWAY_TOOL_TIMEOUT value, parsed as int.
// Returns (0, false) when the environment variable is not set or empty.
// Returns an error when the variable is set but invalid (non-integer or below minimum of 10).
Expand Down
5 changes: 4 additions & 1 deletion internal/server/middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,10 @@ func applyIfConfigured(key string, handler http.HandlerFunc, middleware func(str
//
// For header parsing logic, see internal/auth package which provides:
// - ParseAuthHeader() for extracting API keys and agent IDs
// - ValidateAPIKey() for key validation
// - IsMalformedHeader() for malformed header detection
//
// This middleware validates credentials by directly comparing parsed API key
// values to the configured key.
func authMiddleware(apiKey string, next http.HandlerFunc) http.HandlerFunc {
logAuth.Printf("Initialized auth middleware")
return func(w http.ResponseWriter, r *http.Request) {
Expand Down
Loading