-
Notifications
You must be signed in to change notification settings - Fork 142
Description
Description
When attempting to debug a .NET Isolated Azure Function on macOS using HTTPS, the debugger fails to attach. The preLaunchTask
successfully starts the function host, but the extension's internal health check to the /admin/host/status
endpoint times out after 60 seconds, throwing a RestError: UNABLE_TO_VERIFY_LEAF_SIGNATURE
.
This occurs even when all local configurations are correct, pointing to a bug in how the extension's runtime environment handles TLS connections on macOS.
Key Findings
A detailed investigation revealed the following:
- HTTP Works: Switching the debug task to use HTTP works perfectly, and the debugger attaches instantly.
curl
Works: While the extension is failing, a manualcurl https://localhost:<port>/admin/host/status
command from the terminal succeeds and returns a "Running" state.- Certificate is Trusted: The development certificate has been explicitly trusted via
dotnet dev-certs https --trust
and is verified as trusted in the macOS Keychain. - No Environmental Blocks: The issue persists with the macOS firewall turned off and no other security software or proxies configured.
Root Cause Analysis
An analysis of the extension's source code shows that the startFuncTask
function correctly attempts to disable certificate validation for the localhost
health check. It explicitly sets the { rejectUnauthorized: false }
option before calling sendRequestWithTimeout
.
Despite this correct implementation, the underlying HTTP request still fails with a certificate validation error. This proves that the rejectUnauthorized: false
flag is not being honored by the underlying execution stack (either the specific version of Node.js used by VS Code or the @azure/core-rest-pipeline
library) on macOS.
Like because rejectUnauthorized
is honored by underlying library when it's value is true.
export async function sendRequestWithTimeout(context: IActionContext, options: types.AzExtRequestPrepareOptions, timeout: number, clientInfo: types.AzExtGenericClientInfo): Promise<types.AzExtPipelineResponse> {
const request: PipelineRequest = createPipelineRequest({
...options,
timeout
});
if (options.rejectUnauthorized) {
request.agent = new HttpsAgent({ rejectUnauthorized: options.rejectUnauthorized });
}
const client = await createGenericClient(context, clientInfo, { noRetryPolicy: true, addStatusCodePolicy: true });
return await client.sendRequest(request);
}
Environment
OS Version: MacOS 15.6 (24G84)
VS Code Version: 1.102.1 (Universal)
Extension Version: 1.18.0 (current)
.NET SDK Version: 9.0.303
Core Tools Version: 4.1.0+7ff2567e43c1ae7471cea7394452c1447661e175 (64-bit)
Function Runtime Version: 4.1040.300.25317
Location:
startFuncTask (/Users/***/Code/vscode-azurefunctions/src/commands/pickFuncProcess.ts:158)
Error:
{
name: "RestError",
code: "UNABLE_TO_VERIFY_LEAF_SIGNATURE",
statusCode: undefined,
request: {
url: "https://localhost:<port>/admin/host/status",
body: undefined,
headers: {
_headersMap: {
},
},
method: "GET",
timeout: 500,
multipartBody: undefined,
formData: undefined,
disableKeepAlive: false,
proxySettings: undefined,
streamResponseStatusCodes: undefined,
withCredentials: false,
abortSignal: undefined,
tracingOptions: undefined,
onUploadProgress: undefined,
onDownloadProgress: undefined,
requestId: "d86cf8cc-ebe4-460a-a9f4-33d711eab2ec",
allowInsecureConnection: true,
enableBrowserStreams: false,
agent: undefined,
tlsSettings: undefined,
}
}
Error Stack Trace:
RestError: unable to verify the first certificate
at ClientRequest.<anonymous> (/Users/***/Code/vscode-azurefunctions/node_modules/@azure/core-rest-pipeline/src/nodeHttpClient.ts:241:11)
at Object.onceWrapper (node:events:633:26)
at ClientRequest.emit (node:events:518:28)
at emitErrorEvent (node:_http_client:104:11)
at TLSSocket.socketErrorListener (node:_http_client:518:5)
at TLSSocket.emit (node:events:518:28)
at emitErrorNT (node:internal/streams/destroy:170:8)
at emitErrorCloseNT (node:internal/streams/destroy:129:3)
at processTicksAndRejections (node:internal/process/task_queues:90:21)