From c14886bb2be84c56b3108a9cdee46e08e81baa3e Mon Sep 17 00:00:00 2001 From: Jason Kneen Date: Wed, 5 Feb 2025 15:26:11 +0000 Subject: [PATCH] Fix certificate issue for internal company setup Fixes #1086 Add logic to handle custom certificates for internal company setup. * **crates/goose/src/providers/openai.rs** - Import `Certificate` from `reqwest` and `fs` module. - Add logic to load custom certificate from a specified path. - Update `Client::builder()` to include custom certificate configuration if specified. - Add `OPENAI_CERT_PATH` to the list of configuration keys. * **ui/desktop/src/config.ts** - Import `Certificate` from `electron` and `fs` module. - Add `loadCustomCertificate` function to load custom certificate from a specified path. --- For more details, open the [Copilot Workspace session](https://copilot-workspace.githubnext.com/block/goose/issues/1086?shareId=XXXX-XXXX-XXXX-XXXX). --- crates/goose/src/providers/openai.rs | 19 +++++++++++++++---- ui/desktop/src/config.ts | 14 ++++++++++++++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/crates/goose/src/providers/openai.rs b/crates/goose/src/providers/openai.rs index 35149bff8..244a0903d 100644 --- a/crates/goose/src/providers/openai.rs +++ b/crates/goose/src/providers/openai.rs @@ -1,7 +1,8 @@ use anyhow::Result; use async_trait::async_trait; -use reqwest::Client; +use reqwest::{Client, Certificate}; use serde_json::Value; +use std::fs; use std::time::Duration; use super::base::{ConfigKey, Provider, ProviderMetadata, ProviderUsage, Usage}; @@ -46,9 +47,18 @@ impl OpenAiProvider { let host: String = config .get("OPENAI_HOST") .unwrap_or_else(|_| "https://api.openai.com".to_string()); - let client = Client::builder() - .timeout(Duration::from_secs(600)) - .build()?; + + // Load custom certificate if specified + let cert_path: Option = config.get("OPENAI_CERT_PATH").ok(); + let mut client_builder = Client::builder().timeout(Duration::from_secs(600)); + + if let Some(cert_path) = cert_path { + let cert = fs::read(cert_path)?; + let cert = Certificate::from_pem(&cert)?; + client_builder = client_builder.add_root_certificate(cert); + } + + let client = client_builder.build()?; Ok(Self { client, @@ -93,6 +103,7 @@ impl Provider for OpenAiProvider { vec![ ConfigKey::new("OPENAI_API_KEY", true, true, None), ConfigKey::new("OPENAI_HOST", false, false, Some("https://api.openai.com")), + ConfigKey::new("OPENAI_CERT_PATH", false, false, None), ], ) } diff --git a/ui/desktop/src/config.ts b/ui/desktop/src/config.ts index 907998a24..53d8938b3 100644 --- a/ui/desktop/src/config.ts +++ b/ui/desktop/src/config.ts @@ -1,3 +1,6 @@ +import { Certificate } from 'electron'; +import fs from 'fs'; + // Helper to construct API endpoints export const getApiUrl = (endpoint: string): string => { const baseUrl = window.appConfig.get('GOOSE_API_HOST') + ':' + window.appConfig.get('GOOSE_PORT'); @@ -8,3 +11,14 @@ export const getApiUrl = (endpoint: string): string => { export const getSecretKey = (): string => { return window.appConfig.get('secretKey'); }; + +// Function to load custom certificate +export const loadCustomCertificate = (certPath: string): Certificate | null => { + try { + const cert = fs.readFileSync(certPath); + return Certificate.fromPEM(cert); + } catch (error) { + console.error('Failed to load custom certificate:', error); + return null; + } +};