Skip to content

fix: use caFile variable instead of hardcoded "cacert" in configureTLS#388

Merged
tomasmik merged 3 commits intospacelift-io:mainfrom
bernardm-k:fix/tls-ca-file-bug
Apr 20, 2026
Merged

fix: use caFile variable instead of hardcoded "cacert" in configureTLS#388
tomasmik merged 3 commits intospacelift-io:mainfrom
bernardm-k:fix/tls-ca-file-bug

Conversation

@bernardm-k
Copy link
Copy Markdown
Contributor

Summary

configureTLS() reads SPACELIFT_API_TLS_CA into caFile but passes the hardcoded string "cacert" to os.ReadFile, making the CA bundle feature non-functional. This also adds SSL_CERT_FILE as a fallback.

Changes

internal/cmd/authenticated/client.go

Problem: Line 84 calls os.ReadFile("cacert") instead of os.ReadFile(caFile). Setting SPACELIFT_API_TLS_CA=/etc/ssl/cert.pem tries to read a literal file named cacert in the current directory.

Solution:

  • Fix os.ReadFile to use the caFile variable
  • Add SSL_CERT_FILE env var as a fallback when SPACELIFT_API_TLS_CA is not set
  • SPACELIFT_API_TLS_CA takes precedence when both are set

Impact: Unblocks spacectl usage in sandboxed macOS environments (e.g., restricted CI runners, containerized dev environments) where Security.framework cannot access the Keychain, causing x509: OSStatus -26276. Setting tls.Config.RootCAs to a non-nil pool forces Go's pure-Go certificate verifier, bypassing the Security.framework dependency entirely.

internal/cmd/authenticated/client_test.go (new)

Adds 6 test cases for configureTLS:

  • No env vars set → nil RootCAs (default system behavior)
  • SPACELIFT_API_TLS_CA set → RootCAs populated
  • SSL_CERT_FILE fallback → RootCAs populated
  • Both set → SPACELIFT_API_TLS_CA takes precedence
  • Invalid CA path → error returned
  • Invalid certificate content → errEnvSpaceliftAPIClientCAParse

Net Impact

  • Fixes a bug where SPACELIFT_API_TLS_CA has never worked
  • Adds standard SSL_CERT_FILE support used by other Go tooling
  • No breaking changes — existing behavior without env vars is unchanged

Test plan

  • go test ./internal/cmd/authenticated/... passes
  • Set SPACELIFT_API_TLS_CA=/etc/ssl/cert.pem and verify spacectl profile list works in a sandboxed environment
  • Verify no env vars set still uses system defaults

The SPACELIFT_API_TLS_CA env var was read correctly but os.ReadFile was
called with the literal string "cacert" instead of the caFile variable,
making the feature completely non-functional.

Also adds SSL_CERT_FILE as a fallback env var, which is the standard way
Go programs accept custom CA bundles. This is especially useful in
sandboxed macOS environments where Security.framework cannot access the
Keychain (OSStatus -26276). Setting tls.Config.RootCAs to a non-nil
pool forces Go's pure-Go verifier, bypassing the Keychain dependency.
Covers SPACELIFT_API_TLS_CA, SSL_CERT_FILE fallback, precedence order,
invalid path, and invalid certificate content.
@bernardm-k bernardm-k marked this pull request as ready for review March 6, 2026 17:58
@bernardm-k bernardm-k requested a review from a team as a code owner March 6, 2026 17:58
@tomasmik
Copy link
Copy Markdown
Contributor

@bernardm-k can you fix the tests?

@tomasmik tomasmik self-assigned this Mar 13, 2026
The previous writeTempCA() used a hand-crafted fake PEM that isn't
valid X.509. On macOS it worked because /etc/ssl/cert.pem was used
as a fallback, but on Ubuntu CI (where that file doesn't exist) the
fake cert failed to parse.

Generate a real ECDSA P-256 self-signed CA certificate at test time
using Go's crypto stdlib, which works on all platforms.
@bernardm-k
Copy link
Copy Markdown
Contributor Author

I believe it is fixed now.

@tomasmik tomasmik merged commit a1fb490 into spacelift-io:main Apr 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants