Skip to content

[duplicate-code] Duplicate Code Pattern: Random Hex-Encoded Byte Generation #3110

@github-actions

Description

@github-actions

Part of duplicate code analysis: #3108

Summary

Two package-private functions in different packages implement the same logic: create N random bytes with crypto/rand, hex-encode them, and return the result. The functions differ only in byte count and error-handling strategy, making them candidates for a shared utility.

Duplication Details

Pattern: make([]byte, N)rand.Readhex.EncodeToString

  • Severity: Medium
  • Occurrences: 2 instances across 2 files
  • Locations:
    • internal/cmd/root.go (lines 593–599, function generateRandomAPIKey)
    • internal/middleware/jqschema.go (lines 116–123, function generateRandomID)

Instance 1 — internal/cmd/root.go lines 593–599:

// 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
}

Instance 2 — internal/middleware/jqschema.go lines 116–123:

// generateRandomID generates a random ID for payload storage
func generateRandomID() string {
    bytes := make([]byte, 16)
    if _, err := rand.Read(bytes); err != nil {
        // Fallback to timestamp-based ID if random fails
        return fmt.Sprintf("fallback-%d", os.Getpid())
    }
    return hex.EncodeToString(bytes)
}

The core 3-line pattern (makerand.Readhex.EncodeToString) is identical; the differences are byte count (32 vs 16) and error strategy (propagate error vs PID fallback).

Impact Analysis

  • Maintainability: Minor — both functions are private and simple. Risk is low unless crypto/rand usage policy changes (e.g., switching to rand.Read deprecation in Go 1.20+)
  • Bug Risk: Low — both functions are independently correct
  • Code Bloat: Minor (~10 lines duplicated), but the pattern could recur if more random IDs are needed elsewhere

Refactoring Recommendations

  1. Add a RandomHex(n int) (string, error) helper to internal/strutil (the existing home for string utilities like Truncate and Deduplicate):

    // RandomHex returns a hex-encoded string of n cryptographically random bytes.
    // The returned string has length 2*n.
    func RandomHex(n int) (string, error) {
        b := make([]byte, n)
        if _, err := rand.Read(b); err != nil {
            return "", fmt.Errorf("failed to generate %d random bytes: %w", n, err)
        }
        return hex.EncodeToString(b), nil
    }
  2. Update callers:

    • generateRandomAPIKey() in internal/cmd/root.go: replace body with return strutil.RandomHex(32)
    • generateRandomID() in internal/middleware/jqschema.go: replace with id, err := strutil.RandomHex(16) and apply the PID fallback on error
  3. Alternative: Keep functions as-is if the different error strategies are intentional design choices and the duplication is considered acceptable for the small size. Document the decision with a comment.

Implementation Checklist

  • Add RandomHex (or equivalent) to internal/strutil
  • Update generateRandomAPIKey in internal/cmd/root.go
  • Update generateRandomID in internal/middleware/jqschema.go
  • Add unit tests for RandomHex in internal/strutil
  • Verify no behavioral regression in API key generation or payload ID generation

Parent Issue

See parent analysis report: #3108
Related to #3108

Generated by Duplicate Code Detector ·

  • expires on Apr 10, 2026, 6:01 AM UTC

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions