Skip to content
Draft
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
3 changes: 3 additions & 0 deletions containers/api-proxy/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ Required (at least one):
- `OPENAI_API_KEY` - OpenAI API key for authentication
- `ANTHROPIC_API_KEY` - Anthropic API key for authentication

Optional:
- `COPILOT_API_TARGET` - Target hostname for GitHub Copilot API requests (default: `api.githubcopilot.com`). Useful for GHES deployments.

Set by AWF:
- `HTTP_PROXY` - Squid proxy URL (http://172.30.0.10:3128)
- `HTTPS_PROXY` - Squid proxy URL (http://172.30.0.10:3128)
Expand Down
27 changes: 26 additions & 1 deletion containers/api-proxy/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,37 @@ const OPENAI_API_KEY = process.env.OPENAI_API_KEY;
const ANTHROPIC_API_KEY = process.env.ANTHROPIC_API_KEY;
const COPILOT_GITHUB_TOKEN = process.env.COPILOT_GITHUB_TOKEN;

// Configurable Copilot API target host (supports GHES/GHEC / custom endpoints)
// Priority: COPILOT_API_TARGET env var > auto-derive from GITHUB_SERVER_URL > default
function deriveCopilotApiTarget() {
if (process.env.COPILOT_API_TARGET) {
return process.env.COPILOT_API_TARGET;
}
// For GitHub Enterprise Cloud (*.ghe.com) or GitHub Enterprise Server
// (any GITHUB_SERVER_URL that isn't https://github.com), route to the
// enterprise Copilot API endpoint instead of the individual one.
const serverUrl = process.env.GITHUB_SERVER_URL;
if (serverUrl) {
try {
const hostname = new URL(serverUrl).hostname;
if (hostname !== 'github.com') {
return 'api.enterprise.githubcopilot.com';
}
} catch {
// Invalid URL — fall through to default
}
}
return 'api.githubcopilot.com';
}
const COPILOT_API_TARGET = deriveCopilotApiTarget();

// Squid proxy configuration (set via HTTP_PROXY/HTTPS_PROXY in docker-compose)
const HTTPS_PROXY = process.env.HTTPS_PROXY || process.env.HTTP_PROXY;

logRequest('info', 'startup', {
message: 'Starting AWF API proxy sidecar',
squid_proxy: HTTPS_PROXY || 'not configured',
copilot_api_target: COPILOT_API_TARGET,
providers: {
openai: !!OPENAI_API_KEY,
anthropic: !!ANTHROPIC_API_KEY,
Expand Down Expand Up @@ -433,7 +458,7 @@ if (COPILOT_GITHUB_TOKEN) {
const contentLength = parseInt(req.headers['content-length'], 10) || 0;
if (checkRateLimit(req, res, 'copilot', contentLength)) return;

proxyRequest(req, res, 'api.githubcopilot.com', {
proxyRequest(req, res, COPILOT_API_TARGET, {
'Authorization': `Bearer ${COPILOT_GITHUB_TOKEN}`,
}, 'copilot');
});
Expand Down
7 changes: 7 additions & 0 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -784,6 +784,12 @@ program
' Supports OpenAI (Codex) and Anthropic (Claude) APIs.',
false
)
.option(
'--copilot-api-target <host>',
'Target hostname for GitHub Copilot API requests in the api-proxy sidecar.\n' +
' Defaults to api.githubcopilot.com. Useful for GHES deployments.\n' +
' Can also be set via COPILOT_API_TARGET env var.',
)
.option(
'--rate-limit-rpm <n>',
'Enable rate limiting: max requests per minute per provider (requires --enable-api-proxy)',
Expand Down Expand Up @@ -1064,6 +1070,7 @@ program
openaiApiKey: process.env.OPENAI_API_KEY,
anthropicApiKey: process.env.ANTHROPIC_API_KEY,
copilotGithubToken: process.env.COPILOT_GITHUB_TOKEN,
copilotApiTarget: options.copilotApiTarget || process.env.COPILOT_API_TARGET,
};

// Build rate limit config when API proxy is enabled
Expand Down
10 changes: 10 additions & 0 deletions src/docker-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,9 @@ export function generateDockerCompose(
if (process.env.USER) environment.USER = process.env.USER;
if (process.env.TERM) environment.TERM = process.env.TERM;
if (process.env.XDG_CONFIG_HOME) environment.XDG_CONFIG_HOME = process.env.XDG_CONFIG_HOME;
// Enterprise environment variables — needed for GHEC/GHES Copilot authentication
if (process.env.GITHUB_SERVER_URL) environment.GITHUB_SERVER_URL = process.env.GITHUB_SERVER_URL;
if (process.env.GITHUB_API_URL) environment.GITHUB_API_URL = process.env.GITHUB_API_URL;
}

// Additional environment variables from --env flags (these override everything)
Expand Down Expand Up @@ -977,6 +980,10 @@ export function generateDockerCompose(
...(config.openaiApiKey && { OPENAI_API_KEY: config.openaiApiKey }),
...(config.anthropicApiKey && { ANTHROPIC_API_KEY: config.anthropicApiKey }),
...(config.copilotGithubToken && { COPILOT_GITHUB_TOKEN: config.copilotGithubToken }),
// Configurable Copilot API target (for GHES/GHEC support)
...(config.copilotApiTarget && { COPILOT_API_TARGET: config.copilotApiTarget }),
// Forward GITHUB_SERVER_URL so api-proxy can auto-derive enterprise endpoints
...(process.env.GITHUB_SERVER_URL && { GITHUB_SERVER_URL: process.env.GITHUB_SERVER_URL }),
// Route through Squid to respect domain whitelisting
HTTP_PROXY: `http://${networkConfig.squidIp}:${SQUID_PORT}`,
HTTPS_PROXY: `http://${networkConfig.squidIp}:${SQUID_PORT}`,
Expand Down Expand Up @@ -1050,6 +1057,9 @@ export function generateDockerCompose(
if (config.copilotGithubToken) {
environment.COPILOT_API_URL = `http://${networkConfig.proxyIp}:${API_PROXY_PORTS.COPILOT}`;
logger.debug(`GitHub Copilot API will be proxied through sidecar at http://${networkConfig.proxyIp}:${API_PROXY_PORTS.COPILOT}`);
if (config.copilotApiTarget) {
logger.debug(`Copilot API target overridden to: ${config.copilotApiTarget}`);
}

// Set placeholder token for GitHub Copilot CLI compatibility
// Real authentication happens via COPILOT_API_URL pointing to api-proxy
Expand Down
22 changes: 22 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,28 @@ export interface WrapperConfig {
* @default undefined
*/
copilotGithubToken?: string;

/**
* Target hostname for GitHub Copilot API requests (used by API proxy sidecar)
*
* When enableApiProxy is true, this hostname is passed to the Node.js sidecar
* as `COPILOT_API_TARGET`. The proxy will forward Copilot API requests to this host
* instead of the default `api.githubcopilot.com`.
*
* Useful for GitHub Enterprise Server (GHES) deployments where the Copilot API
* endpoint differs from the public default.
*
* Can be set via:
* - CLI flag: `--copilot-api-target <host>`
* - Environment variable: `COPILOT_API_TARGET`
*
* @default 'api.githubcopilot.com'
* @example
* ```bash
* awf --enable-api-proxy --copilot-api-target api.github.mycompany.com -- command
* ```
*/
copilotApiTarget?: string;
}

/**
Expand Down