Fix broken proxy configuration for default kernel fetch. (#747)

- Closes #466.

## Type of Change
- [x] Bug fix
- [ ] New feature  
- [ ] Breaking change
- [ ] Documentation update

## Motivation and Context
Proxy logic worked well enough for CI but broken in general.

## Testing
- [x] Tested locally
- [x] Added/updated tests
- [ ] Added/updated docs
This commit is contained in:
J Logan
2025-10-10 10:17:42 -07:00
committed by GitHub
parent 0d3f20c4ca
commit bc70b39182
7 changed files with 119 additions and 23 deletions
-1
View File
@@ -67,7 +67,6 @@ jobs:
- name: Test the container project
run: |
launchctl setenv HTTP_PROXY $HTTP_PROXY
APP_ROOT=$(mktemp -d -p "${RUNNER_TEMP}")
trap 'rm -rf "${APP_ROOT}"; echo Removing data directory ${APP_ROOT}' EXIT
echo "Created data directory ${APP_ROOT}"
+3 -3
View File
@@ -1,5 +1,5 @@
{
"originHash" : "e8a26d708e3d286b0e29d74d94b6ff1539848a7a9fd209a230faedae5e285003",
"originHash" : "ee0892935fd158d90844c467fb84568e8fd24f3fe7b04d49504fdf99e6322df6",
"pins" : [
{
"identity" : "async-http-client",
@@ -15,8 +15,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/containerization.git",
"state" : {
"revision" : "992ed9f5aa3b0e875ef8ac6b605a4c352218463b",
"version" : "0.9.1"
"revision" : "d0383eb5bf97f27bceb51538597194b020bc8945",
"version" : "0.10.0"
}
},
{
+1 -1
View File
@@ -23,7 +23,7 @@ import PackageDescription
let releaseVersion = ProcessInfo.processInfo.environment["RELEASE_VERSION"] ?? "0.0.0"
let gitCommit = ProcessInfo.processInfo.environment["GIT_COMMIT"] ?? "unspecified"
let builderShimVersion = "0.6.1"
let scVersion = "0.9.1"
let scVersion = "0.10.0"
let package = Package(
name: "container",
+8 -12
View File
@@ -49,24 +49,20 @@ public struct FileDownloader {
}
})
let client = FileDownloader.createClient()
let client = FileDownloader.createClient(url: url)
_ = try await client.execute(request: request, delegate: delegate).get()
try await client.shutdown()
}
private static func createClient() -> HTTPClient {
private static func createClient(url: URL) -> HTTPClient {
var httpConfiguration = HTTPClient.Configuration()
let proxyConfig: HTTPClient.Configuration.Proxy? = {
let proxyEnv = ProcessInfo.processInfo.environment["HTTP_PROXY"]
guard let proxyEnv else {
return nil
if let host = url.host {
let proxyURL = ProxyUtils.proxyFromEnvironment(scheme: url.scheme, host: host)
if let proxyURL, let proxyHost = proxyURL.host {
httpConfiguration.proxy = HTTPClient.Configuration.Proxy.server(host: proxyHost, port: proxyURL.port ?? 8080)
}
guard let url = URL(string: proxyEnv), let host = url.host(), let port = url.port else {
return nil
}
return .server(host: host, port: port)
}()
httpConfiguration.proxy = proxyConfig
}
return HTTPClient(eventLoopGroupProvider: .singleton, configuration: httpConfiguration)
}
}
@@ -69,9 +69,8 @@ extension Application {
args.append("start")
let apiServerDataUrl = appRoot.appending(path: "apiserver")
try! FileManager.default.createDirectory(at: apiServerDataUrl, withIntermediateDirectories: true)
var env = ProcessInfo.processInfo.environment.filter { key, _ in
key.hasPrefix("CONTAINER_")
}
var env = PluginLoader.filterEnvironment()
env[ApplicationRoot.environmentName] = appRoot.path(percentEncoded: false)
env[InstallRoot.environmentName] = installRoot.path(percentEncoded: false)
+17 -3
View File
@@ -196,6 +196,12 @@ extension PluginLoader {
}
extension PluginLoader {
public static let proxyKeys = Set([
"http_proxy", "HTTP_PROXY",
"https_proxy", "HTTPS_PROXY",
"no_proxy", "NO_PROXY",
])
public func registerWithLaunchd(
plugin: Plugin,
pluginStateRoot: URL? = nil,
@@ -212,9 +218,8 @@ extension PluginLoader {
log?.info("Registering plugin", metadata: ["id": "\(id)"])
let rootURL = pluginStateRoot ?? self.pluginResourceRoot.appending(path: plugin.name)
try FileManager.default.createDirectory(at: rootURL, withIntermediateDirectories: true)
var env = ProcessInfo.processInfo.environment.filter { key, _ in
key.hasPrefix("CONTAINER_")
}
var env = Self.filterEnvironment()
env[ApplicationRoot.environmentName] = appRoot.path(percentEncoded: false)
env[InstallRoot.environmentName] = installRoot.path(percentEncoded: false)
@@ -244,4 +249,13 @@ extension PluginLoader {
log?.info("Deregistering plugin", metadata: ["id": "\(plugin.getLaunchdLabel())"])
try ServiceManager.deregister(fullServiceLabel: label)
}
public static func filterEnvironment(
env: [String: String] = ProcessInfo.processInfo.environment,
additionalAllowKeys: Set<String> = Self.proxyKeys
) -> [String: String] {
env.filter { key, _ in
key.hasPrefix("CONTAINER_") || additionalAllowKeys.contains(key)
}
}
}
@@ -85,6 +85,94 @@ struct PluginLoaderTest {
#expect(loader.findPlugin(name: "throw") == nil)
}
@Test
func testFilterEnvironmentWithContainerPrefix() async throws {
let env = [
"CONTAINER_FOO": "bar",
"CONTAINER_BAZ": "qux",
"OTHER_VAR": "value",
]
let filtered = PluginLoader.filterEnvironment(env: env, additionalAllowKeys: [])
#expect(filtered == ["CONTAINER_FOO": "bar", "CONTAINER_BAZ": "qux"])
}
@Test
func testFilterEnvironmentWithProxyKeys() async throws {
let env = [
"http_proxy": "http://proxy:8080",
"HTTP_PROXY": "http://proxy:8080",
"https_proxy": "https://proxy:8443",
"HTTPS_PROXY": "https://proxy:8443",
"no_proxy": "localhost,127.0.0.1",
"NO_PROXY": "localhost,127.0.0.1",
"OTHER_VAR": "value",
]
let filtered = PluginLoader.filterEnvironment(env: env)
#expect(
filtered == [
"http_proxy": "http://proxy:8080",
"HTTP_PROXY": "http://proxy:8080",
"https_proxy": "https://proxy:8443",
"HTTPS_PROXY": "https://proxy:8443",
"no_proxy": "localhost,127.0.0.1",
"NO_PROXY": "localhost,127.0.0.1",
])
}
@Test
func testFilterEnvironmentWithBothContainerAndProxy() async throws {
let env = [
"CONTAINER_FOO": "bar",
"http_proxy": "http://proxy:8080",
"OTHER_VAR": "value",
"ANOTHER_VAR": "value2",
]
let filtered = PluginLoader.filterEnvironment(env: env)
#expect(
filtered == [
"CONTAINER_FOO": "bar",
"http_proxy": "http://proxy:8080",
])
}
@Test
func testFilterEnvironmentWithCustomAllowKeys() async throws {
let env = [
"CONTAINER_FOO": "bar",
"CUSTOM_KEY": "custom_value",
"OTHER_VAR": "value",
]
let filtered = PluginLoader.filterEnvironment(env: env, additionalAllowKeys: ["CUSTOM_KEY"])
#expect(
filtered == [
"CONTAINER_FOO": "bar",
"CUSTOM_KEY": "custom_value",
])
}
@Test
func testFilterEnvironmentEmpty() async throws {
let filtered = PluginLoader.filterEnvironment(env: [:])
#expect(filtered.isEmpty)
}
@Test
func testFilterEnvironmentNoMatches() async throws {
let env = [
"PATH": "/usr/bin",
"HOME": "/Users/test",
"USER": "testuser",
]
let filtered = PluginLoader.filterEnvironment(env: env, additionalAllowKeys: [])
#expect(filtered.isEmpty)
}
private func setupMock(tempURL: URL) throws -> MockPluginFactory {
let cliConfig = PluginConfig(abstract: "cli", author: "CLI", servicesConfig: nil)
let cliPlugin: Plugin = Plugin(binaryURL: URL(filePath: "/bin/cli"), config: cliConfig)