fix: trust the certificates named by SSL_CERT_FILE on Windows and macOS - #141
fix: trust the certificates named by SSL_CERT_FILE on Windows and macOS#141pjcdawkins wants to merge 2 commits into
Conversation
Go reads that variable only on Unix; elsewhere it verifies through the operating system. The legacy CLI reads it on every platform, through Composer\CaBundle, so the two parts of the CLI disagreed about which certificates to trust, and a command implemented in Go failed where the same command implemented in PHP worked. An unusable file is reported as a warning rather than being fatal, and the system certificates are used, as before. Written by Claude Code.
|
📋 PR Summary This PR adds an Changes
|
There was a problem hiding this comment.
Pull request overview
This PR aligns TLS certificate trust behavior between the Go and legacy PHP halves of the Upsun CLI by honoring SSL_CERT_FILE on Windows and macOS (where Go does not read it automatically), so commands implemented in Go (e.g., init) behave consistently with legacy commands.
Changes:
- Add
internal/certswithUseEnvCertFile()to configure the default HTTP transport to trust the PEM bundle referenced bySSL_CERT_FILEon Windows/macOS. - Invoke
certs.UseEnvCertFile()early incmd/platform/main.go, warning (non-fatal) if the file is unreadable or invalid. - Add tests in
internal/certscovering trust/no-trust behavior and error cases for invalid/missing PEM input.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| internal/certs/certs.go | Introduces transport configuration to use SSL_CERT_FILE roots on platforms where Go doesn’t read it. |
| internal/certs/certs_test.go | Adds unit tests validating trust behavior and error handling for the cert-file logic. |
| cmd/platform/main.go | Wires the cert-file logic into CLI startup so Go HTTP requests follow the same trust model as legacy PHP. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if transport.TLSClientConfig == nil { | ||
| transport.TLSClientConfig = &tls.Config{MinVersion: tls.VersionTLS12} | ||
| } |
Written by Claude Code.
Related to #110. Independent of #139 and #140, which deal with the Windows certificate store.
The problem
The legacy CLI trusts the certificates named by
SSL_CERT_FILEon every platform, becauseComposer\CaBundlechecks that variable first when it resolves a bundle. The Go part of the CLI only trusts it on Unix: Go readsSSL_CERT_FILEincrypto/x509/root_unix.go, and on Windows and macOS it verifies through the operating system instead.So for someone whose organization gives them a CA bundle as a file,
upsun environment:listworks andupsun initdoes not, on the same machine, for the same reason — with no hint that the two halves of the CLI resolve certificates differently.The change
certs.UseEnvCertFile()points the default HTTP transport at the file, on the platforms where Go does not read the variable itself. Every request the Go part makes goes throughhttp.DefaultTransport— the API client, the update check, the config fetch, andinit— so one call at startup covers all of them.The file replaces the system certificates rather than adding to them. That matches Go's own behavior on Unix and
Composer\CaBundle's everywhere, so the CLI resolves certificates the same way whichever part serves the command.An unusable file is a warning on stderr rather than a fatal error, and the system certificates are used, which is what both Go and
Composer\CaBundledo with one.Tests
internal/certsserves HTTPS with a certificate the system does not trust, and checks it is rejected with no file set and accepted with the file set. The error cases cover an unreadable path and a file holding no certificates.Written by Claude Code.