Skip to content

Commit 4865f82

Browse files
authored
Harden Copilot proxy auth normalization to avoid malformed Authorization headers (#3322)
* Initial plan * fix: normalize copilot auth token placeholders --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
1 parent fa1f55a commit 4865f82

2 files changed

Lines changed: 29 additions & 4 deletions

File tree

containers/api-proxy/providers/copilot.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,11 @@ const { URL } = require('url');
3232
// it means the sidecar received a dummy key (not a real BYOK credential) and should
3333
// fall back to COPILOT_GITHUB_TOKEN as the sole auth source.
3434
const COPILOT_PLACEHOLDER_TOKEN = 'ghu_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
35+
const COPILOT_DUMMY_BYOK_KEY = 'dummy-byok-key-for-offline-mode';
3536

3637
/**
37-
* Strip any accidental "Bearer " prefix from a raw credential value and trim
38+
* Strip any accidental "Bearer " or "token " prefix from a raw credential
39+
* value and trim
3840
* surrounding whitespace. Returns undefined when the result is empty so that
3941
* callers can use `|| undefined` fall-through cleanly.
4042
*
@@ -45,7 +47,7 @@ const COPILOT_PLACEHOLDER_TOKEN = 'ghu_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
4547
* @returns {string|undefined}
4648
*/
4749
function stripBearerPrefix(value) {
48-
return ((value || '').replace(/^\s*Bearer\s+/i, '').trim()) || undefined;
50+
return ((value || '').replace(/^\s*(?:Bearer|token)\s+/i, '').trim()) || undefined;
4951
}
5052

5153
/**
@@ -60,7 +62,7 @@ function stripBearerPrefix(value) {
6062
*/
6163
function resolveApiKey(env) {
6264
const key = stripBearerPrefix(env.COPILOT_API_KEY);
63-
return key === COPILOT_PLACEHOLDER_TOKEN ? undefined : key;
65+
return key === COPILOT_PLACEHOLDER_TOKEN || key === COPILOT_DUMMY_BYOK_KEY ? undefined : key;
6466
}
6567

6668
/**
@@ -367,5 +369,6 @@ module.exports = {
367369
deriveGitHubApiTarget,
368370
deriveGitHubApiBasePath,
369371
COPILOT_PLACEHOLDER_TOKEN,
372+
COPILOT_DUMMY_BYOK_KEY,
370373
},
371374
};

containers/api-proxy/server.auth.test.js

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,13 @@
66

77
const { shouldStripHeader } = require('./proxy-utils');
88
const {
9-
_testing: { resolveCopilotAuthToken, resolveApiKey, stripBearerPrefix, COPILOT_PLACEHOLDER_TOKEN },
9+
_testing: {
10+
resolveCopilotAuthToken,
11+
resolveApiKey,
12+
stripBearerPrefix,
13+
COPILOT_PLACEHOLDER_TOKEN,
14+
COPILOT_DUMMY_BYOK_KEY,
15+
},
1016
createCopilotAdapter,
1117
} = require('./providers/copilot');
1218
const { sanitizeNullToolCallTypes } = require('./body-transform');
@@ -55,6 +61,11 @@ describe('stripBearerPrefix', () => {
5561
expect(stripBearerPrefix('BEARER sk-or-v1-abc')).toBe('sk-or-v1-abc');
5662
});
5763

64+
it('strips "token " prefix case-insensitively', () => {
65+
expect(stripBearerPrefix('token sk-or-v1-abc')).toBe('sk-or-v1-abc');
66+
expect(stripBearerPrefix('TOKEN sk-or-v1-abc')).toBe('sk-or-v1-abc');
67+
});
68+
5869
it('strips leading whitespace before "Bearer "', () => {
5970
expect(stripBearerPrefix(' Bearer sk-or-v1-abc')).toBe('sk-or-v1-abc');
6071
});
@@ -155,6 +166,13 @@ describe('resolveCopilotAuthToken', () => {
155166
COPILOT_API_KEY: COPILOT_PLACEHOLDER_TOKEN,
156167
})).toBe('gho_real_token');
157168
});
169+
170+
it('uses COPILOT_GITHUB_TOKEN when COPILOT_API_KEY is the offline BYOK dummy key', () => {
171+
expect(resolveCopilotAuthToken({
172+
COPILOT_GITHUB_TOKEN: 'gho_real_token',
173+
COPILOT_API_KEY: COPILOT_DUMMY_BYOK_KEY,
174+
})).toBe('gho_real_token');
175+
});
158176
});
159177

160178
describe('resolveApiKey', () => {
@@ -166,6 +184,10 @@ describe('resolveApiKey', () => {
166184
expect(resolveApiKey({ COPILOT_API_KEY: COPILOT_PLACEHOLDER_TOKEN })).toBeUndefined();
167185
});
168186

187+
it('returns undefined when COPILOT_API_KEY is the offline BYOK dummy key', () => {
188+
expect(resolveApiKey({ COPILOT_API_KEY: COPILOT_DUMMY_BYOK_KEY })).toBeUndefined();
189+
});
190+
169191
it('returns undefined when COPILOT_API_KEY is not set', () => {
170192
expect(resolveApiKey({})).toBeUndefined();
171193
});

0 commit comments

Comments
 (0)