Skip to content

[Duplicate Code] getUnconfiguredHealthResponse body structure duplicated across three provider adapters #4635

Description

@github-actions

Duplicate Code Opportunity

Summary

  • Pattern: getUnconfiguredHealthResponse() in three provider adapters returns identically structured objects { statusCode: 503, body: { status: 'not_configured', service: 'awf-api-proxy-{name}', error: '...' } } with no shared builder. This is inconsistent with the existing makeProviderNotConfiguredResponse() helper in proxy-utils.js that already centralises the getUnconfiguredResponse() pattern.
  • Locations: containers/api-proxy/providers/anthropic.js, containers/api-proxy/providers/copilot.js, containers/api-proxy/providers/gemini.js
  • Impact: ~28 method-body lines across 3 providers (10 + 10 + 6). Any future change to the health endpoint response shape (e.g., adding a port field for diagnostics, changing the 503 code, or adding a docs_url) requires touching three files.

Evidence

containers/api-proxy/providers/anthropic.js (lines 237–248)

getUnconfiguredHealthResponse() {
  if (oidcRequested) {
    return {
      statusCode: 503,
      body: { status: 'unavailable', service: 'awf-api-proxy-anthropic', error: oidcUnavailableError },
    };
  }
  return {
    statusCode: 503,
    body: { status: 'not_configured', service: 'awf-api-proxy-anthropic', error: 'ANTHROPIC_API_KEY not configured in api-proxy sidecar' },
  };
},

containers/api-proxy/providers/copilot.js (lines 297–308)

getUnconfiguredHealthResponse() {
  if (oidcConfigured) {
    return {
      statusCode: 503,
      body: { status: 'not_configured', service: 'awf-api-proxy-copilot', error: `Copilot OIDC token (${authProvider}) not yet available in api-proxy sidecar` },
    };
  }
  return {
    statusCode: 503,
    body: { status: 'not_configured', service: 'awf-api-proxy-copilot', error: 'COPILOT_GITHUB_TOKEN or COPILOT_PROVIDER_API_KEY not configured in api-proxy sidecar' },
  };
},

containers/api-proxy/providers/gemini.js (lines 92–97)

getUnconfiguredHealthResponse() {
  return {
    statusCode: 503,
    body: { status: 'not_configured', service: 'awf-api-proxy-gemini', error: 'GEMINI_API_KEY not configured in api-proxy sidecar' },
  };
},

For comparison, proxy-utils.js already has makeProviderNotConfiguredResponse(provider, port, message) that centralises the corresponding getUnconfiguredResponse() pattern — but no equivalent exists for getUnconfiguredHealthResponse.

Suggested Refactoring

Add a makeProviderHealthNotConfiguredResponse helper to containers/api-proxy/proxy-utils.js:

/**
 * Build the standard /health response body for an unconfigured provider.
 *
 * `@param` {string} provider - Provider name (e.g. 'anthropic', 'gemini')
 * `@param` {string} status   - 'not_configured' | 'unavailable'
 * `@param` {string} message  - Human-readable error message
 * `@returns` {{ statusCode: number, body: object }}
 */
function makeProviderHealthNotConfiguredResponse(provider, status, message) {
  return {
    statusCode: 503,
    body: {
      status,
      service: `awf-api-proxy-${provider}`,
      error: message,
    },
  };
}

Then each provider's getUnconfiguredHealthResponse becomes:

// anthropic (base case)
return makeProviderHealthNotConfiguredResponse(
  'anthropic', 'not_configured',
  'ANTHROPIC_API_KEY not configured in api-proxy sidecar'
);

// gemini
return makeProviderHealthNotConfiguredResponse(
  'gemini', 'not_configured',
  'GEMINI_API_KEY not configured in api-proxy sidecar'
);

The OIDC branch variants in anthropic and copilot would continue to use inline objects or call the helper with 'unavailable' status.

Affected Files

  • containers/api-proxy/providers/anthropic.js — lines 237–248
  • containers/api-proxy/providers/copilot.js — lines 297–308
  • containers/api-proxy/providers/gemini.js — lines 92–97
  • containers/api-proxy/proxy-utils.js — add new helper and export

Effort Estimate

Low


Detected by Duplicate Code Detector workflow. Run date: 2026-06-09

Generated by Duplicate Code Detector · 440.1 AIC · ⊞ 26.9K ·

  • expires on Jul 9, 2026, 10:17 PM UTC

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    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