@google/gemini-cli-core 0.66.0-nightly.20261020.g76e4d7c04 → 0.66.0-preview.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/docs/cli/plan-mode.md +1 -1
- package/dist/docs/tools/mcp-server.md +6 -0
- package/dist/src/generated/git-commit.d.ts +2 -2
- package/dist/src/generated/git-commit.js +2 -2
- package/dist/src/generated/git-commit.js.map +1 -1
- package/dist/src/mcp/oauth-private-network.test.d.ts +6 -0
- package/dist/src/mcp/oauth-private-network.test.js +505 -0
- package/dist/src/mcp/oauth-private-network.test.js.map +1 -0
- package/dist/src/mcp/oauth-provider.d.ts +1 -0
- package/dist/src/mcp/oauth-provider.js +98 -74
- package/dist/src/mcp/oauth-provider.js.map +1 -1
- package/dist/src/mcp/oauth-utils.d.ts +10 -2
- package/dist/src/mcp/oauth-utils.js +39 -14
- package/dist/src/mcp/oauth-utils.js.map +1 -1
- package/dist/src/mcp/stored-token-provider.js +1 -3
- package/dist/src/mcp/stored-token-provider.js.map +1 -1
- package/dist/src/services/shellExecutionService.js +4 -2
- package/dist/src/services/shellExecutionService.js.map +1 -1
- package/dist/src/services/shellExecutionService.test.js +17 -2
- package/dist/src/services/shellExecutionService.test.js.map +1 -1
- package/dist/src/tools/mcp-client.js +22 -13
- package/dist/src/tools/mcp-client.js.map +1 -1
- package/dist/src/tools/mcp-client.test.js +8 -4
- package/dist/src/tools/mcp-client.test.js.map +1 -1
- package/dist/src/utils/errors.js +20 -6
- package/dist/src/utils/errors.js.map +1 -1
- package/dist/src/utils/errors.test.js +92 -0
- package/dist/src/utils/errors.test.js.map +1 -1
- package/dist/src/utils/fetch.d.ts +6 -0
- package/dist/src/utils/fetch.js +33 -0
- package/dist/src/utils/fetch.js.map +1 -1
- package/dist/src/utils/gitUtils.js +4 -1
- package/dist/src/utils/gitUtils.js.map +1 -1
- package/dist/src/utils/gitUtils.test.js +71 -0
- package/dist/src/utils/gitUtils.test.js.map +1 -1
- package/dist/src/utils/oauth-flow.d.ts +6 -2
- package/dist/src/utils/oauth-flow.js +4 -2
- package/dist/src/utils/oauth-flow.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/dist/google-gemini-cli-core-0.66.0-nightly.20261013.g204db94ae.tgz +0 -0
|
@@ -340,7 +340,7 @@ if [ -f "$plan_path" ]; then
|
|
|
340
340
|
filename="$(date +%s)_$(basename "$plan_path")"
|
|
341
341
|
|
|
342
342
|
# Upload the plan to GCS in the background so it doesn't block the CLI
|
|
343
|
-
|
|
343
|
+
gcloud storage cp "$plan_path" "gs://my-audit-bucket/gemini-plans/$filename" > /dev/null 2>&1 &
|
|
344
344
|
fi
|
|
345
345
|
|
|
346
346
|
# AfterTool hooks should generally allow the flow to continue
|
|
@@ -433,6 +433,12 @@ Use the `/mcp auth` command to manage OAuth authentication:
|
|
|
433
433
|
random port, e.g., `http://localhost:<random-port>/oauth/callback`)
|
|
434
434
|
- **`tokenParamName`** (string): Query parameter name for tokens in SSE URLs
|
|
435
435
|
- **`audiences`** (string[]): Audiences the token is valid for
|
|
436
|
+
- **`allowPrivateNetwork`** (boolean): Allow OAuth discovery, registration,
|
|
437
|
+
authorization, and token endpoints that resolve to private enterprise network
|
|
438
|
+
addresses (RFC 1918, RFC 6598 Carrier-Grade NAT, RFC 4193 IPv6 Unique Local,
|
|
439
|
+
and `.internal` or `.local` domains). Defaults to `false`. HTTPS is still
|
|
440
|
+
required for non-loopback endpoints, and link-local (`169.254.0.0/16`,
|
|
441
|
+
`fe80::/10`) and loopback (`127.0.0.0/8`, `::1`) addresses remain restricted.
|
|
436
442
|
|
|
437
443
|
#### Token management
|
|
438
444
|
|
|
@@ -3,5 +3,5 @@
|
|
|
3
3
|
* Copyright 2026 Google LLC
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
|
-
export declare const GIT_COMMIT_INFO = "
|
|
7
|
-
export declare const CLI_VERSION = "0.66.0-
|
|
6
|
+
export declare const GIT_COMMIT_INFO = "b041de017";
|
|
7
|
+
export declare const CLI_VERSION = "0.66.0-preview.0";
|
|
@@ -5,6 +5,6 @@
|
|
|
5
5
|
*/
|
|
6
6
|
// This file is auto-generated by the build script (scripts/generate-git-commit-info.js)
|
|
7
7
|
// Do not edit this file manually.
|
|
8
|
-
export const GIT_COMMIT_INFO = '
|
|
9
|
-
export const CLI_VERSION = '0.66.0-
|
|
8
|
+
export const GIT_COMMIT_INFO = 'b041de017';
|
|
9
|
+
export const CLI_VERSION = '0.66.0-preview.0';
|
|
10
10
|
//# sourceMappingURL=git-commit.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"git-commit.js","sourceRoot":"","sources":["../../../src/generated/git-commit.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,wFAAwF;AACxF,kCAAkC;AAClC,MAAM,CAAC,MAAM,eAAe,GAAG,WAAW,CAAC;AAC3C,MAAM,CAAC,MAAM,WAAW,GAAG,
|
|
1
|
+
{"version":3,"file":"git-commit.js","sourceRoot":"","sources":["../../../src/generated/git-commit.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,wFAAwF;AACxF,kCAAkC;AAClC,MAAM,CAAC,MAAM,eAAe,GAAG,WAAW,CAAC;AAC3C,MAAM,CAAC,MAAM,WAAW,GAAG,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,505 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
7
|
+
const mockOpenBrowserSecurely = vi.hoisted(() => vi.fn());
|
|
8
|
+
const mockHttpServer = vi.hoisted(() => ({
|
|
9
|
+
listen: vi.fn(),
|
|
10
|
+
close: vi.fn(),
|
|
11
|
+
on: vi.fn(),
|
|
12
|
+
address: vi.fn(() => ({ address: '127.0.0.1', family: 'IPv4', port: 7777 })),
|
|
13
|
+
listening: false,
|
|
14
|
+
}));
|
|
15
|
+
vi.mock('../utils/secure-browser-launcher.js', () => ({
|
|
16
|
+
openBrowserSecurely: mockOpenBrowserSecurely,
|
|
17
|
+
}));
|
|
18
|
+
vi.mock('../utils/authConsent.js', () => ({
|
|
19
|
+
getConsentForOauth: vi.fn(() => Promise.resolve(false)),
|
|
20
|
+
}));
|
|
21
|
+
vi.mock('./oauth-token-storage.js', () => ({
|
|
22
|
+
MCPOAuthTokenStorage: vi.fn(),
|
|
23
|
+
}));
|
|
24
|
+
vi.mock('node:dns/promises', () => ({
|
|
25
|
+
lookup: vi.fn(),
|
|
26
|
+
}));
|
|
27
|
+
vi.mock('node:http', async (importOriginal) => {
|
|
28
|
+
const actual = await importOriginal();
|
|
29
|
+
return { ...actual, createServer: vi.fn(() => mockHttpServer) };
|
|
30
|
+
});
|
|
31
|
+
import * as http from 'node:http';
|
|
32
|
+
import * as dnsPromises from 'node:dns/promises';
|
|
33
|
+
import { isIP } from 'node:net';
|
|
34
|
+
import { MCPOAuthProvider } from './oauth-provider.js';
|
|
35
|
+
import { MCPOAuthTokenStorage } from './oauth-token-storage.js';
|
|
36
|
+
import { OAuthUtils, OAuthSecurityError, validateOAuthEndpointUrl, } from './oauth-utils.js';
|
|
37
|
+
import { DynamicStoredOAuthProvider } from './stored-token-provider.js';
|
|
38
|
+
import { connectToMcpServer } from '../tools/mcp-client.js';
|
|
39
|
+
import { isEnterprisePrivateAddress, isAddressPrivate, } from '../utils/fetch.js';
|
|
40
|
+
import { getConsentForOauth } from '../utils/authConsent.js';
|
|
41
|
+
import { coreEvents } from '../utils/events.js';
|
|
42
|
+
import { WorkspaceContext } from '../utils/workspaceContext.js';
|
|
43
|
+
const SERVER_NAME = 'enterprise-jira-mcp';
|
|
44
|
+
const ENTERPRISE_HOST = 'jira-app-2938-default.aip-use5.prj-dv-host.dev.internal.example.com';
|
|
45
|
+
const ENTERPRISE_PRIVATE_IP = '10.28.128.77';
|
|
46
|
+
const MCP_SERVER_URL = `https://${ENTERPRISE_HOST}/mcp`;
|
|
47
|
+
const PRM_URL = `https://${ENTERPRISE_HOST}/.well-known/oauth-protected-resource/mcp`;
|
|
48
|
+
const AS_METADATA_URL = `https://${ENTERPRISE_HOST}/.well-known/oauth-authorization-server`;
|
|
49
|
+
const PRIVATE_AUTHORIZATION_URL = `https://${ENTERPRISE_HOST}/oauth/authorize`;
|
|
50
|
+
const PRIVATE_TOKEN_URL = `https://${ENTERPRISE_HOST}/oauth/token`;
|
|
51
|
+
const PUBLIC_IP = '93.184.216.34';
|
|
52
|
+
const MIXED_ANSWER_HOST = 'mixed-answers.corp.example.com';
|
|
53
|
+
const REMEDIATION_HINT = 'Set "oauth.allowPrivateNetwork": true in settings.json for this MCP server if it is on a trusted private network.';
|
|
54
|
+
const dnsBranchMessage = (url, address = ENTERPRISE_PRIVATE_IP, includeHint = true) => `OAuth endpoint "${url}" resolves to private network address "${address}" which is blocked.${includeHint ? ` ${REMEDIATION_HINT}` : ''}`;
|
|
55
|
+
const literalBranchMessage = (url, includeHint = true) => `OAuth endpoint "${url}" points to private or reserved IP address which is blocked.${includeHint ? ` ${REMEDIATION_HINT}` : ''}`;
|
|
56
|
+
const mockLookup = vi.mocked(dnsPromises.lookup);
|
|
57
|
+
const DNS_ANSWERS = {
|
|
58
|
+
[ENTERPRISE_HOST]: [{ address: ENTERPRISE_PRIVATE_IP, family: 4 }],
|
|
59
|
+
'sso.corp.internal': [{ address: ENTERPRISE_PRIVATE_IP, family: 4 }],
|
|
60
|
+
'auth.mycompany.local': [{ address: '192.168.10.25', family: 4 }],
|
|
61
|
+
'metadata.corp.internal': [{ address: '169.254.169.254', family: 4 }],
|
|
62
|
+
[MIXED_ANSWER_HOST]: [
|
|
63
|
+
{ address: ENTERPRISE_PRIVATE_IP, family: 4 },
|
|
64
|
+
{ address: '169.254.169.254', family: 4 },
|
|
65
|
+
],
|
|
66
|
+
};
|
|
67
|
+
let routes = {};
|
|
68
|
+
const requestLog = [];
|
|
69
|
+
const unexpectedRequests = [];
|
|
70
|
+
const mockFetch = vi.fn(async (input, init) => {
|
|
71
|
+
const url = typeof input === 'string'
|
|
72
|
+
? input
|
|
73
|
+
: input instanceof URL
|
|
74
|
+
? input.toString()
|
|
75
|
+
: input.url;
|
|
76
|
+
const key = `${(init?.method ?? 'GET').toUpperCase()} ${url}`;
|
|
77
|
+
requestLog.push(key);
|
|
78
|
+
const handler = routes[key];
|
|
79
|
+
if (!handler) {
|
|
80
|
+
unexpectedRequests.push(key);
|
|
81
|
+
throw new TypeError(`fetch failed: no test route for ${key}`);
|
|
82
|
+
}
|
|
83
|
+
return handler();
|
|
84
|
+
});
|
|
85
|
+
function createStubStorage(credentials) {
|
|
86
|
+
return {
|
|
87
|
+
getCredentials: vi.fn(async () => credentials),
|
|
88
|
+
isTokenExpired: vi.fn(() => true),
|
|
89
|
+
deleteCredentials: vi.fn(async () => { }),
|
|
90
|
+
saveToken: vi.fn(async () => { }),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function providerWith(storage) {
|
|
94
|
+
return new MCPOAuthProvider(storage);
|
|
95
|
+
}
|
|
96
|
+
function expiredPrivateIdpCredentials() {
|
|
97
|
+
return {
|
|
98
|
+
serverName: SERVER_NAME,
|
|
99
|
+
token: {
|
|
100
|
+
accessToken: 'expired-access-token',
|
|
101
|
+
tokenType: 'Bearer',
|
|
102
|
+
refreshToken: 'refresh-token-1',
|
|
103
|
+
expiresAt: Date.now() - 60_000,
|
|
104
|
+
},
|
|
105
|
+
clientId: 'gemini-cli',
|
|
106
|
+
tokenUrl: PRIVATE_TOKEN_URL,
|
|
107
|
+
mcpServerUrl: MCP_SERVER_URL,
|
|
108
|
+
updatedAt: Date.now() - 3_600_000,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
async function captureRejection(promise) {
|
|
112
|
+
try {
|
|
113
|
+
await promise;
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
if (error instanceof Error) {
|
|
117
|
+
return error;
|
|
118
|
+
}
|
|
119
|
+
throw new Error(`Non-Error rejection: ${String(error)}`);
|
|
120
|
+
}
|
|
121
|
+
throw new Error('Expected the promise to reject, but it resolved.');
|
|
122
|
+
}
|
|
123
|
+
describe('MCP OAuth endpoints on private enterprise networks', () => {
|
|
124
|
+
let feedbackSpy;
|
|
125
|
+
beforeEach(() => {
|
|
126
|
+
vi.clearAllMocks();
|
|
127
|
+
routes = {};
|
|
128
|
+
requestLog.length = 0;
|
|
129
|
+
unexpectedRequests.length = 0;
|
|
130
|
+
vi.stubGlobal('fetch', mockFetch);
|
|
131
|
+
vi.spyOn(console, 'log').mockImplementation(() => { });
|
|
132
|
+
vi.spyOn(console, 'debug').mockImplementation(() => { });
|
|
133
|
+
vi.spyOn(console, 'warn').mockImplementation(() => { });
|
|
134
|
+
vi.spyOn(console, 'error').mockImplementation(() => { });
|
|
135
|
+
feedbackSpy = vi
|
|
136
|
+
.spyOn(coreEvents, 'emitFeedback')
|
|
137
|
+
.mockImplementation(() => { });
|
|
138
|
+
mockLookup.mockImplementation(async (hostname) => {
|
|
139
|
+
const answer = DNS_ANSWERS[hostname];
|
|
140
|
+
if (answer) {
|
|
141
|
+
return answer;
|
|
142
|
+
}
|
|
143
|
+
const family = isIP(hostname);
|
|
144
|
+
if (family !== 0) {
|
|
145
|
+
return [{ address: hostname, family }];
|
|
146
|
+
}
|
|
147
|
+
return [{ address: PUBLIC_IP, family: 4 }];
|
|
148
|
+
});
|
|
149
|
+
mockHttpServer.listen.mockImplementation((_port, callback) => {
|
|
150
|
+
callback?.();
|
|
151
|
+
return mockHttpServer;
|
|
152
|
+
});
|
|
153
|
+
vi.mocked(getConsentForOauth).mockResolvedValue(false);
|
|
154
|
+
});
|
|
155
|
+
afterEach(() => {
|
|
156
|
+
vi.unstubAllGlobals();
|
|
157
|
+
vi.restoreAllMocks();
|
|
158
|
+
});
|
|
159
|
+
// -------------------------------------------------------------------------
|
|
160
|
+
// 0. Address Classifier Unit Tests (isEnterprisePrivateAddress)
|
|
161
|
+
// -------------------------------------------------------------------------
|
|
162
|
+
describe('isEnterprisePrivateAddress classifier', () => {
|
|
163
|
+
it.each([
|
|
164
|
+
['10.0.0.1'],
|
|
165
|
+
['10.28.128.77'],
|
|
166
|
+
['172.16.0.1'],
|
|
167
|
+
['172.31.255.254'],
|
|
168
|
+
['192.168.1.1'],
|
|
169
|
+
['100.64.0.1'],
|
|
170
|
+
['100.127.255.254'],
|
|
171
|
+
['fc00::1'],
|
|
172
|
+
['fd12:3456:789a::1'],
|
|
173
|
+
['[fd00::1]'],
|
|
174
|
+
['::ffff:10.28.128.77'],
|
|
175
|
+
['sso.corp.internal'],
|
|
176
|
+
['SSO.CORP.INTERNAL'],
|
|
177
|
+
['auth.mycompany.local'],
|
|
178
|
+
])('returns true for enterprise private target %s while keeping isAddressPrivate true', (target) => {
|
|
179
|
+
expect(isEnterprisePrivateAddress(target)).toBe(true);
|
|
180
|
+
expect(isAddressPrivate(target.toLowerCase())).toBe(true);
|
|
181
|
+
});
|
|
182
|
+
it.each([
|
|
183
|
+
['127.0.0.1'],
|
|
184
|
+
['::1'],
|
|
185
|
+
['localhost'],
|
|
186
|
+
['sub.localhost'],
|
|
187
|
+
['169.254.169.254'],
|
|
188
|
+
['fe80::1'],
|
|
189
|
+
['::ffff:169.254.169.254'],
|
|
190
|
+
['::ffff:127.0.0.1'],
|
|
191
|
+
['224.0.0.1'],
|
|
192
|
+
['255.255.255.255'],
|
|
193
|
+
['0.0.0.0'],
|
|
194
|
+
['::'],
|
|
195
|
+
['198.18.0.1'],
|
|
196
|
+
['198.19.255.254'],
|
|
197
|
+
['93.184.216.34'],
|
|
198
|
+
['auth.example.com'],
|
|
199
|
+
])('returns false for restricted or public target %s', (target) => {
|
|
200
|
+
expect(isEnterprisePrivateAddress(target)).toBe(false);
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
// -------------------------------------------------------------------------
|
|
204
|
+
// 1. Default Behavior: rejects private-network OAuth endpoints without opt-in
|
|
205
|
+
// -------------------------------------------------------------------------
|
|
206
|
+
describe('default behavior: rejects private-network OAuth endpoints when allowPrivateNetwork is omitted or false', () => {
|
|
207
|
+
it('R1a /mcp auth, WWW-Authenticate discovery: rejects the private discovery URL with actionable hint before requesting it', async () => {
|
|
208
|
+
routes[`HEAD ${MCP_SERVER_URL}`] = () => new Response(null, {
|
|
209
|
+
status: 401,
|
|
210
|
+
headers: {
|
|
211
|
+
'www-authenticate': `Bearer resource_metadata="${PRM_URL}"`,
|
|
212
|
+
},
|
|
213
|
+
});
|
|
214
|
+
const storage = createStubStorage(null);
|
|
215
|
+
const error = await captureRejection(providerWith(storage).authenticate(SERVER_NAME, { enabled: false }, MCP_SERVER_URL));
|
|
216
|
+
expect(error).toBeInstanceOf(OAuthSecurityError);
|
|
217
|
+
expect(error.message).toBe(dnsBranchMessage(PRM_URL));
|
|
218
|
+
expect(requestLog).toEqual([`HEAD ${MCP_SERVER_URL}`]);
|
|
219
|
+
expect(unexpectedRequests).toEqual([]);
|
|
220
|
+
expect(mockLookup).toHaveBeenCalledWith(ENTERPRISE_HOST, { all: true });
|
|
221
|
+
expect(vi.mocked(http.createServer)).not.toHaveBeenCalled();
|
|
222
|
+
expect(getConsentForOauth).not.toHaveBeenCalled();
|
|
223
|
+
expect(mockOpenBrowserSecurely).not.toHaveBeenCalled();
|
|
224
|
+
expect(storage.saveToken).not.toHaveBeenCalled();
|
|
225
|
+
});
|
|
226
|
+
it('R1b /mcp auth, well-known discovery (HEAD not 401): rejects the private discovery URL before requesting it', async () => {
|
|
227
|
+
routes[`HEAD ${MCP_SERVER_URL}`] = () => new Response(null, { status: 405 });
|
|
228
|
+
const error = await captureRejection(providerWith(createStubStorage(null)).authenticate(SERVER_NAME, { enabled: false }, MCP_SERVER_URL));
|
|
229
|
+
expect(error.message).toBe(dnsBranchMessage(PRM_URL));
|
|
230
|
+
expect(requestLog).toEqual([`HEAD ${MCP_SERVER_URL}`]);
|
|
231
|
+
expect(unexpectedRequests).toEqual([]);
|
|
232
|
+
expect(getConsentForOauth).not.toHaveBeenCalled();
|
|
233
|
+
expect(mockOpenBrowserSecurely).not.toHaveBeenCalled();
|
|
234
|
+
});
|
|
235
|
+
it('R2 automatic 401 path: discovery from WWW-Authenticate rejects the private discovery URL', async () => {
|
|
236
|
+
const error = await captureRejection(OAuthUtils.discoverOAuthFromWWWAuthenticate(`Bearer resource_metadata="${PRM_URL}"`, MCP_SERVER_URL));
|
|
237
|
+
expect(error.message).toBe(dnsBranchMessage(PRM_URL));
|
|
238
|
+
expect(requestLog).toEqual([]);
|
|
239
|
+
});
|
|
240
|
+
it('R3a explicit endpoints on a literal private IP: rejected before callback server or consent, without DNS or requests', async () => {
|
|
241
|
+
const authorizationUrl = `https://${ENTERPRISE_PRIVATE_IP}/oauth/authorize`;
|
|
242
|
+
const config = {
|
|
243
|
+
enabled: true,
|
|
244
|
+
clientId: 'gemini-cli',
|
|
245
|
+
authorizationUrl,
|
|
246
|
+
tokenUrl: `https://${ENTERPRISE_PRIVATE_IP}/oauth/token`,
|
|
247
|
+
};
|
|
248
|
+
const error = await captureRejection(providerWith(createStubStorage(null)).authenticate(SERVER_NAME, config, MCP_SERVER_URL));
|
|
249
|
+
expect(error.message).toBe(literalBranchMessage(authorizationUrl));
|
|
250
|
+
expect(requestLog).toEqual([]);
|
|
251
|
+
expect(mockLookup).not.toHaveBeenCalled();
|
|
252
|
+
expect(vi.mocked(http.createServer)).not.toHaveBeenCalled();
|
|
253
|
+
expect(getConsentForOauth).not.toHaveBeenCalled();
|
|
254
|
+
expect(mockOpenBrowserSecurely).not.toHaveBeenCalled();
|
|
255
|
+
});
|
|
256
|
+
it('R3b explicit endpoints on a hostname resolving to a private IP: rejected before callback server or consent', async () => {
|
|
257
|
+
const config = {
|
|
258
|
+
enabled: true,
|
|
259
|
+
clientId: 'gemini-cli',
|
|
260
|
+
authorizationUrl: PRIVATE_AUTHORIZATION_URL,
|
|
261
|
+
tokenUrl: PRIVATE_TOKEN_URL,
|
|
262
|
+
};
|
|
263
|
+
const error = await captureRejection(providerWith(createStubStorage(null)).authenticate(SERVER_NAME, config, MCP_SERVER_URL));
|
|
264
|
+
expect(error.message).toBe(dnsBranchMessage(PRIVATE_AUTHORIZATION_URL));
|
|
265
|
+
expect(requestLog).toEqual([]);
|
|
266
|
+
expect(vi.mocked(http.createServer)).not.toHaveBeenCalled();
|
|
267
|
+
expect(getConsentForOauth).not.toHaveBeenCalled();
|
|
268
|
+
});
|
|
269
|
+
it('R4 token refresh against a private token endpoint without opt-in: rejected and stored credentials are deleted', async () => {
|
|
270
|
+
const storage = createStubStorage(expiredPrivateIdpCredentials());
|
|
271
|
+
const token = await providerWith(storage).getValidToken(SERVER_NAME, {});
|
|
272
|
+
expect(token).toBeNull();
|
|
273
|
+
expect(requestLog).toEqual([]);
|
|
274
|
+
expect(storage.saveToken).not.toHaveBeenCalled();
|
|
275
|
+
expect(storage.deleteCredentials).toHaveBeenCalledTimes(1);
|
|
276
|
+
expect(storage.deleteCredentials).toHaveBeenCalledWith(SERVER_NAME);
|
|
277
|
+
expect(feedbackSpy).toHaveBeenCalledWith('error', 'Failed to refresh auth token.', expect.objectContaining({
|
|
278
|
+
message: dnsBranchMessage(PRIVATE_TOKEN_URL),
|
|
279
|
+
}));
|
|
280
|
+
});
|
|
281
|
+
it.each([
|
|
282
|
+
['RFC 1918 10.0.0.0/8', 'https://10.0.0.1/oauth/token', true],
|
|
283
|
+
['RFC 1918 172.16.0.0/12', 'https://172.16.0.1/oauth/token', true],
|
|
284
|
+
['RFC 1918 192.168.0.0/16', 'https://192.168.1.1/oauth/token', true],
|
|
285
|
+
['CGNAT 100.64.0.0/10', 'https://100.64.0.10/oauth/token', true],
|
|
286
|
+
['RFC 4193 fc00::/7', 'https://[fd00::1]/oauth/token', true],
|
|
287
|
+
['.internal name', 'https://sso.corp.internal/oauth/token', true],
|
|
288
|
+
['.local name', 'https://auth.mycompany.local/oauth/token', true],
|
|
289
|
+
[
|
|
290
|
+
'link-local 169.254.0.0/16',
|
|
291
|
+
'https://169.254.169.254/oauth/token',
|
|
292
|
+
false,
|
|
293
|
+
],
|
|
294
|
+
])('R5 scope: rejects %s without opt-in', async (_label, url, includeHint) => {
|
|
295
|
+
await expect(validateOAuthEndpointUrl(url)).rejects.toThrow(literalBranchMessage(url, includeHint));
|
|
296
|
+
await expect(validateOAuthEndpointUrl(url, { allowPrivateNetwork: false })).rejects.toThrow(literalBranchMessage(url, includeHint));
|
|
297
|
+
});
|
|
298
|
+
it('C1 control: a public OAuth endpoint is accepted by the same harness', async () => {
|
|
299
|
+
const url = 'https://auth.example.com/oauth/authorize';
|
|
300
|
+
await expect(validateOAuthEndpointUrl(url)).resolves.toBe(url);
|
|
301
|
+
});
|
|
302
|
+
it('C2 control: a loopback discovery URL is accepted when the MCP server is loopback', async () => {
|
|
303
|
+
const url = 'http://localhost:8080/.well-known/oauth-protected-resource/mcp';
|
|
304
|
+
await expect(validateOAuthEndpointUrl(url, { allowLoopback: true })).resolves.toBe(url);
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
// -------------------------------------------------------------------------
|
|
308
|
+
// 2. Opt-in Behavior: per-server oauth.allowPrivateNetwork: true
|
|
309
|
+
// -------------------------------------------------------------------------
|
|
310
|
+
describe('opt-in behavior: per-server oauth.allowPrivateNetwork: true', () => {
|
|
311
|
+
it('A1 /mcp auth discovery for a private MCP server with opt-in reaches the consent step', async () => {
|
|
312
|
+
routes[`HEAD ${MCP_SERVER_URL}`] = () => new Response(null, {
|
|
313
|
+
status: 401,
|
|
314
|
+
headers: {
|
|
315
|
+
'www-authenticate': `Bearer resource_metadata="${PRM_URL}"`,
|
|
316
|
+
},
|
|
317
|
+
});
|
|
318
|
+
routes[`GET ${PRM_URL}`] = () => Response.json({
|
|
319
|
+
resource: MCP_SERVER_URL,
|
|
320
|
+
authorization_servers: [`https://${ENTERPRISE_HOST}`],
|
|
321
|
+
});
|
|
322
|
+
const PRIVATE_REGISTRATION_URL = `https://${ENTERPRISE_HOST}/oauth/register`;
|
|
323
|
+
routes[`GET ${AS_METADATA_URL}`] = () => Response.json({
|
|
324
|
+
issuer: `https://${ENTERPRISE_HOST}`,
|
|
325
|
+
authorization_endpoint: PRIVATE_AUTHORIZATION_URL,
|
|
326
|
+
token_endpoint: PRIVATE_TOKEN_URL,
|
|
327
|
+
registration_endpoint: PRIVATE_REGISTRATION_URL,
|
|
328
|
+
});
|
|
329
|
+
routes[`POST ${PRIVATE_REGISTRATION_URL}`] = () => Response.json({
|
|
330
|
+
client_id: 'dynamic-private-client',
|
|
331
|
+
redirect_uris: ['http://localhost:33418/oauth/callback'],
|
|
332
|
+
});
|
|
333
|
+
const config = {
|
|
334
|
+
enabled: false,
|
|
335
|
+
clientId: 'gemini-cli',
|
|
336
|
+
allowPrivateNetwork: true,
|
|
337
|
+
};
|
|
338
|
+
const error = await captureRejection(providerWith(createStubStorage(null)).authenticate(SERVER_NAME, config, MCP_SERVER_URL));
|
|
339
|
+
expect(error.message).toBe('Authentication cancelled by user.');
|
|
340
|
+
expect(getConsentForOauth).toHaveBeenCalledTimes(1);
|
|
341
|
+
expect(unexpectedRequests).toEqual([]);
|
|
342
|
+
});
|
|
343
|
+
it('A2 explicit private endpoints with opt-in reach the consent step', async () => {
|
|
344
|
+
const config = {
|
|
345
|
+
enabled: true,
|
|
346
|
+
clientId: 'gemini-cli',
|
|
347
|
+
authorizationUrl: PRIVATE_AUTHORIZATION_URL,
|
|
348
|
+
tokenUrl: PRIVATE_TOKEN_URL,
|
|
349
|
+
allowPrivateNetwork: true,
|
|
350
|
+
};
|
|
351
|
+
const error = await captureRejection(providerWith(createStubStorage(null)).authenticate(SERVER_NAME, config, MCP_SERVER_URL));
|
|
352
|
+
expect(error.message).toBe('Authentication cancelled by user.');
|
|
353
|
+
expect(getConsentForOauth).toHaveBeenCalledTimes(1);
|
|
354
|
+
});
|
|
355
|
+
it('A3 token refresh with opt-in succeeds and preserves the stored credentials', async () => {
|
|
356
|
+
routes[`POST ${PRIVATE_TOKEN_URL}`] = () => Response.json({
|
|
357
|
+
access_token: 'new-access-token',
|
|
358
|
+
token_type: 'Bearer',
|
|
359
|
+
expires_in: 3600,
|
|
360
|
+
});
|
|
361
|
+
const storage = createStubStorage(expiredPrivateIdpCredentials());
|
|
362
|
+
const config = { allowPrivateNetwork: true };
|
|
363
|
+
const token = await providerWith(storage).getValidToken(SERVER_NAME, config);
|
|
364
|
+
expect(token).toBe('new-access-token');
|
|
365
|
+
expect(storage.deleteCredentials).not.toHaveBeenCalled();
|
|
366
|
+
expect(storage.saveToken).toHaveBeenCalledTimes(1);
|
|
367
|
+
expect(requestLog).toEqual([`POST ${PRIVATE_TOKEN_URL}`]);
|
|
368
|
+
});
|
|
369
|
+
it('A4 validator with opt-in accepts DNS-resolved RFC 1918, literal RFC 1918, CGNAT, RFC 4193, and .internal/.local endpoints', async () => {
|
|
370
|
+
const options = {
|
|
371
|
+
allowPrivateNetwork: true,
|
|
372
|
+
};
|
|
373
|
+
for (const url of [
|
|
374
|
+
'https://10.0.0.1/oauth/token',
|
|
375
|
+
'https://172.16.0.1/oauth/token',
|
|
376
|
+
'https://192.168.1.1/oauth/token',
|
|
377
|
+
'https://100.64.0.1/oauth/token',
|
|
378
|
+
'https://[fd00::1]/oauth/token',
|
|
379
|
+
'https://sso.corp.internal/oauth/token',
|
|
380
|
+
'https://auth.mycompany.local/oauth/token',
|
|
381
|
+
PRIVATE_TOKEN_URL,
|
|
382
|
+
]) {
|
|
383
|
+
await expect(validateOAuthEndpointUrl(url, options)).resolves.toBe(url);
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
});
|
|
387
|
+
// -------------------------------------------------------------------------
|
|
388
|
+
// 3. Unconditional Guardrails: still rejected even with allowPrivateNetwork: true
|
|
389
|
+
// -------------------------------------------------------------------------
|
|
390
|
+
describe('guardrails: restricted ranges and protocol checks still enforced when allowPrivateNetwork is true', () => {
|
|
391
|
+
const optIn = { allowPrivateNetwork: true };
|
|
392
|
+
it('G1 link-local / instance metadata literals (169.254.169.254, fe80::/10) stay rejected', async () => {
|
|
393
|
+
await expect(validateOAuthEndpointUrl('https://169.254.169.254/computeMetadata/v1', optIn)).rejects.toThrow(OAuthSecurityError);
|
|
394
|
+
await expect(validateOAuthEndpointUrl('https://[fe80::1]/oauth/token', optIn)).rejects.toThrow(OAuthSecurityError);
|
|
395
|
+
});
|
|
396
|
+
it('G2 a hostname or .internal domain resolving to link-local or mixed DNS answers stays rejected', async () => {
|
|
397
|
+
await expect(validateOAuthEndpointUrl(`https://${MIXED_ANSWER_HOST}/oauth/token`, optIn)).rejects.toThrow(dnsBranchMessage(`https://${MIXED_ANSWER_HOST}/oauth/token`, '169.254.169.254', false));
|
|
398
|
+
await expect(validateOAuthEndpointUrl('https://metadata.corp.internal/oauth/token', optIn)).rejects.toThrow(dnsBranchMessage('https://metadata.corp.internal/oauth/token', '169.254.169.254', false));
|
|
399
|
+
});
|
|
400
|
+
it('G3 plain HTTP to a private address stays rejected', async () => {
|
|
401
|
+
await expect(validateOAuthEndpointUrl(`http://${ENTERPRISE_PRIVATE_IP}/oauth/token`, optIn)).rejects.toThrow(/OAuth endpoints must use HTTPS unless connecting to localhost\.$/);
|
|
402
|
+
});
|
|
403
|
+
it('G4 loopback (127.0.0.1, ::1, localhost, .localhost) stays rejected unless allowLoopback is set', async () => {
|
|
404
|
+
await expect(validateOAuthEndpointUrl('https://127.0.0.1/oauth/token', optIn)).rejects.toThrow('Loopback OAuth endpoint "https://127.0.0.1/oauth/token" is not allowed for remote MCP servers.');
|
|
405
|
+
await expect(validateOAuthEndpointUrl('https://app.localhost/oauth/token', optIn)).rejects.toThrow(literalBranchMessage('https://app.localhost/oauth/token', false));
|
|
406
|
+
});
|
|
407
|
+
it('G5 multicast (224.0.0.1) and benchmark testing (198.18.0.1) addresses stay rejected', async () => {
|
|
408
|
+
await expect(validateOAuthEndpointUrl('https://224.0.0.1/oauth/token', optIn)).rejects.toThrow(literalBranchMessage('https://224.0.0.1/oauth/token', false));
|
|
409
|
+
await expect(validateOAuthEndpointUrl('https://198.18.0.1/oauth/token', optIn)).rejects.toThrow(literalBranchMessage('https://198.18.0.1/oauth/token', false));
|
|
410
|
+
});
|
|
411
|
+
it('G6 cross-origin resource_metadata stays rejected even with allowPrivateNetwork: true', async () => {
|
|
412
|
+
await expect(OAuthUtils.discoverOAuthFromWWWAuthenticate('Bearer resource_metadata="https://other-internal.corp.internal/.well-known/oauth-protected-resource"', MCP_SERVER_URL, { allowPrivateNetwork: true })).rejects.toThrow(/does not match expected origin/);
|
|
413
|
+
});
|
|
414
|
+
});
|
|
415
|
+
// -------------------------------------------------------------------------
|
|
416
|
+
// 4. Plumbing Verification: DynamicStoredOAuthProvider & Automatic 401 OAuth
|
|
417
|
+
// -------------------------------------------------------------------------
|
|
418
|
+
describe('plumbing verification: background token refresh and automatic 401 OAuth', () => {
|
|
419
|
+
it('P1 DynamicStoredOAuthProvider.tokens() forwards allowPrivateNetwork during refresh even when oauth.enabled is not set', async () => {
|
|
420
|
+
routes[`POST ${PRIVATE_TOKEN_URL}`] = () => Response.json({
|
|
421
|
+
access_token: 'refreshed-private-token',
|
|
422
|
+
token_type: 'Bearer',
|
|
423
|
+
expires_in: 3600,
|
|
424
|
+
});
|
|
425
|
+
const storage = createStubStorage(expiredPrivateIdpCredentials());
|
|
426
|
+
vi.mocked(MCPOAuthTokenStorage).mockImplementation(() => storage);
|
|
427
|
+
const getValidTokenWithMetadataSpy = vi.spyOn(MCPOAuthProvider.prototype, 'getValidTokenWithMetadata');
|
|
428
|
+
const serverConfig = {
|
|
429
|
+
url: MCP_SERVER_URL,
|
|
430
|
+
type: 'http',
|
|
431
|
+
oauth: {
|
|
432
|
+
allowPrivateNetwork: true,
|
|
433
|
+
},
|
|
434
|
+
};
|
|
435
|
+
const dynamicProvider = new DynamicStoredOAuthProvider(SERVER_NAME, serverConfig);
|
|
436
|
+
const tokens = await dynamicProvider.tokens();
|
|
437
|
+
expect(getValidTokenWithMetadataSpy).toHaveBeenCalledWith(SERVER_NAME, {
|
|
438
|
+
allowPrivateNetwork: true,
|
|
439
|
+
});
|
|
440
|
+
expect(tokens?.access_token).toBe('refreshed-private-token');
|
|
441
|
+
expect(storage.deleteCredentials).not.toHaveBeenCalled();
|
|
442
|
+
expect(storage.saveToken).toHaveBeenCalledTimes(1);
|
|
443
|
+
});
|
|
444
|
+
it('P2 connectToMcpServer automatic 401 OAuth flow forwards allowPrivateNetwork to discovery and authenticate()', async () => {
|
|
445
|
+
routes[`POST ${MCP_SERVER_URL}`] = () => new Response('Unauthorized', {
|
|
446
|
+
status: 401,
|
|
447
|
+
headers: {
|
|
448
|
+
'www-authenticate': `Bearer resource_metadata="${PRM_URL}"`,
|
|
449
|
+
},
|
|
450
|
+
});
|
|
451
|
+
routes[`HEAD ${MCP_SERVER_URL}`] = () => new Response(null, {
|
|
452
|
+
status: 401,
|
|
453
|
+
headers: {
|
|
454
|
+
'www-authenticate': `Bearer resource_metadata="${PRM_URL}"`,
|
|
455
|
+
},
|
|
456
|
+
});
|
|
457
|
+
routes[`GET ${PRM_URL}`] = () => Response.json({
|
|
458
|
+
resource: MCP_SERVER_URL,
|
|
459
|
+
authorization_servers: [`https://${ENTERPRISE_HOST}`],
|
|
460
|
+
});
|
|
461
|
+
const PRIVATE_REGISTRATION_URL = `https://${ENTERPRISE_HOST}/oauth/register`;
|
|
462
|
+
routes[`GET ${AS_METADATA_URL}`] = () => Response.json({
|
|
463
|
+
issuer: `https://${ENTERPRISE_HOST}`,
|
|
464
|
+
authorization_endpoint: PRIVATE_AUTHORIZATION_URL,
|
|
465
|
+
token_endpoint: PRIVATE_TOKEN_URL,
|
|
466
|
+
registration_endpoint: PRIVATE_REGISTRATION_URL,
|
|
467
|
+
});
|
|
468
|
+
routes[`POST ${PRIVATE_REGISTRATION_URL}`] = () => Response.json({
|
|
469
|
+
client_id: 'dynamic-private-client',
|
|
470
|
+
redirect_uris: ['http://localhost:33418/oauth/callback'],
|
|
471
|
+
});
|
|
472
|
+
const storage = createStubStorage(null);
|
|
473
|
+
vi.mocked(MCPOAuthTokenStorage).mockImplementation(() => storage);
|
|
474
|
+
const authenticateSpy = vi.spyOn(MCPOAuthProvider.prototype, 'authenticate');
|
|
475
|
+
const discoverWWWAuthSpy = vi.spyOn(OAuthUtils, 'discoverOAuthFromWWWAuthenticate');
|
|
476
|
+
const serverConfig = {
|
|
477
|
+
httpUrl: MCP_SERVER_URL,
|
|
478
|
+
oauth: {
|
|
479
|
+
enabled: true,
|
|
480
|
+
allowPrivateNetwork: true,
|
|
481
|
+
},
|
|
482
|
+
};
|
|
483
|
+
const workspaceContext = new WorkspaceContext(process.cwd());
|
|
484
|
+
const mockContext = {
|
|
485
|
+
sanitizationConfig: {
|
|
486
|
+
enableEnvironmentVariableRedaction: false,
|
|
487
|
+
allowedEnvironmentVariables: [],
|
|
488
|
+
blockedEnvironmentVariables: [],
|
|
489
|
+
},
|
|
490
|
+
emitMcpDiagnostic: vi.fn(),
|
|
491
|
+
isTrustedFolder: () => true,
|
|
492
|
+
};
|
|
493
|
+
await expect(connectToMcpServer('0.0.1', SERVER_NAME, serverConfig, false, workspaceContext, mockContext)).rejects.toThrow(`Failed to handle automatic OAuth for server '${SERVER_NAME}'`);
|
|
494
|
+
expect(discoverWWWAuthSpy).toHaveBeenCalledWith(`Bearer resource_metadata="${PRM_URL}"`, MCP_SERVER_URL, { allowPrivateNetwork: true });
|
|
495
|
+
expect(authenticateSpy).toHaveBeenCalledWith(SERVER_NAME, expect.objectContaining({
|
|
496
|
+
enabled: true,
|
|
497
|
+
authorizationUrl: PRIVATE_AUTHORIZATION_URL,
|
|
498
|
+
tokenUrl: PRIVATE_TOKEN_URL,
|
|
499
|
+
allowPrivateNetwork: true,
|
|
500
|
+
}), MCP_SERVER_URL);
|
|
501
|
+
expect(getConsentForOauth).toHaveBeenCalledTimes(1);
|
|
502
|
+
});
|
|
503
|
+
});
|
|
504
|
+
});
|
|
505
|
+
//# sourceMappingURL=oauth-private-network.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth-private-network.test.js","sourceRoot":"","sources":["../../../src/mcp/oauth-private-network.test.ts"],"names":[],"mappings":"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"}
|