mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-13 15:40:57 -07:00
refactor(a2a): standardize safeFetch signature and simplify usage in registry and client manager
This commit is contained in:
@@ -66,7 +66,7 @@ const a2aDispatcher = new UndiciAgent({
|
||||
});
|
||||
const a2aFetch: typeof fetch = (input, init) => {
|
||||
const nodeInit: NodeFetchInit = { ...init, dispatcher: a2aDispatcher };
|
||||
return fetch(input, nodeInit);
|
||||
return fetch(input, nodeInit as RequestInit);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -531,14 +531,10 @@ describe('AgentRegistry', () => {
|
||||
});
|
||||
|
||||
expect(call).toBeDefined();
|
||||
// Verify that the wrapper delegates to safeFetch
|
||||
const options = call?.[0] as { fetchImpl?: typeof fetch };
|
||||
|
||||
// We can't easily spy on safeFetch because it's an exported function,
|
||||
// but we've verified it is provided via options.
|
||||
expect(typeof options?.fetchImpl).toBe('function');
|
||||
// Use safeFetch to satisfy the unused import check.
|
||||
expect(safeFetch).toBeDefined();
|
||||
// We passed safeFetch directly
|
||||
expect(options?.fetchImpl).toBe(safeFetch);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -166,15 +166,8 @@ export class AgentRegistry {
|
||||
// We use a dedicated resolver here to fetch the card for hashing.
|
||||
// This is separate from loadAgent to keep hashing logic isolated.
|
||||
// We provide safeFetch to ensure SSRF and DNS rebinding protection.
|
||||
// We wrap it to match the signature expected by the SDK.
|
||||
const fetchImpl: typeof fetch = (input, init) => {
|
||||
if (input instanceof Request) {
|
||||
return safeFetch(input.url, init);
|
||||
}
|
||||
return safeFetch(input, init);
|
||||
};
|
||||
const resolver = new DefaultAgentCardResolver({
|
||||
fetchImpl,
|
||||
fetchImpl: safeFetch,
|
||||
});
|
||||
const { baseUrl, path } = splitAgentCardUrl(agent.agentCardUrl);
|
||||
const rawCard = await resolver.resolve(baseUrl, path);
|
||||
|
||||
@@ -191,7 +191,7 @@ export function isAddressPrivate(address: string): boolean {
|
||||
* Prevents access to private/internal networks at the connection level.
|
||||
*/
|
||||
export async function safeFetch(
|
||||
url: string | URL,
|
||||
input: RequestInfo | URL,
|
||||
init?: RequestInit,
|
||||
): Promise<Response> {
|
||||
const nodeInit: NodeFetchInit = {
|
||||
@@ -200,13 +200,19 @@ export async function safeFetch(
|
||||
};
|
||||
|
||||
try {
|
||||
return await fetch(url, nodeInit);
|
||||
return await fetch(input, nodeInit);
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
// Re-map refusing to connect errors to standard FetchError
|
||||
if (error.message.includes('Refusing to connect to private IP address')) {
|
||||
const urlString =
|
||||
input instanceof Request
|
||||
? input.url
|
||||
: typeof input === 'string'
|
||||
? input
|
||||
: input.toString();
|
||||
throw new FetchError(
|
||||
`Access to private network is blocked: ${url.toString()}`,
|
||||
`Access to private network is blocked: ${urlString}`,
|
||||
'ERR_PRIVATE_NETWORK',
|
||||
{ cause: error },
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user