Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/PROXY_MODE.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ awmg proxy \
# Trust the generated CA and point gh at the proxy
export GH_HOST=localhost:8443
export NODE_EXTRA_CA_CERTS=/tmp/gh-aw/mcp-logs/proxy-tls/ca.crt
export SSL_CERT_FILE=/tmp/gh-aw/mcp-logs/proxy-tls/ca.crt
export GIT_SSL_CAINFO=/tmp/gh-aw/mcp-logs/proxy-tls/ca.crt
gh issue list -R org/repo
```

Expand Down Expand Up @@ -167,6 +169,8 @@ docker run --rm -p 8443:8443 \
# Trust the CA cert from the mounted log volume
export GH_HOST=localhost:8443
export NODE_EXTRA_CA_CERTS=/tmp/proxy-logs/proxy-tls/ca.crt
export SSL_CERT_FILE=/tmp/proxy-logs/proxy-tls/ca.crt
export GIT_SSL_CAINFO=/tmp/proxy-logs/proxy-tls/ca.crt
gh issue list -R org/repo
```

Expand Down Expand Up @@ -219,6 +223,8 @@ When `--tls` is enabled, the proxy writes to `--tls-dir` (default: `<log-dir>/pr
**gh CLI / Node.js**:
```bash
export NODE_EXTRA_CA_CERTS=/tmp/gh-aw/mcp-logs/proxy-tls/ca.crt
export SSL_CERT_FILE=/tmp/gh-aw/mcp-logs/proxy-tls/ca.crt
export GIT_SSL_CAINFO=/tmp/gh-aw/mcp-logs/proxy-tls/ca.crt
```

**System-wide (Ubuntu)**:
Expand Down
27 changes: 27 additions & 0 deletions internal/cmd/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"os"
"os/signal"
"path/filepath"
"strings"
"syscall"
"time"

Expand All @@ -24,6 +25,14 @@ import (

var logProxyCmd = logger.New("cmd:proxy")

var tlsTrustEnvKeys = []string{
"NODE_EXTRA_CA_CERTS",
"SSL_CERT_FILE",
"GIT_SSL_CAINFO",
"CURL_CA_BUNDLE",
"REQUESTS_CA_BUNDLE",
}

// Proxy subcommand flag variables
var (
proxyGuardWasm string
Expand Down Expand Up @@ -223,6 +232,9 @@ func runProxy(cmd *cobra.Command, args []string) error {
if err != nil {
return fmt.Errorf("failed to generate TLS certificates: %w", err)
}
if err := configureTLSTrustEnvironment(tlsCfg.CACertPath); err != nil {
return err
}
logger.LogInfo("startup", "TLS certificates generated: ca=%s", tlsCfg.CACertPath)
}

Expand Down Expand Up @@ -268,6 +280,8 @@ func runProxy(cmd *cobra.Command, args []string) error {
fmt.Fprintf(os.Stderr, "\nConnect with:\n")
fmt.Fprintf(os.Stderr, " export GH_HOST=%s\n", clientAddr(actualAddr))
fmt.Fprintf(os.Stderr, " export NODE_EXTRA_CA_CERTS=%s\n", tlsCfg.CACertPath)
fmt.Fprintf(os.Stderr, " export SSL_CERT_FILE=%s\n", tlsCfg.CACertPath)
fmt.Fprintf(os.Stderr, " export GIT_SSL_CAINFO=%s\n", tlsCfg.CACertPath)
fmt.Fprintf(os.Stderr, " gh issue list -R org/repo\n\n")
} else {
fmt.Fprintf(os.Stderr, "\nConnect with:\n")
Expand Down Expand Up @@ -302,3 +316,16 @@ func clientAddr(addr string) string {
}
return addr
}

func configureTLSTrustEnvironment(caCertPath string) error {
if strings.ContainsAny(caCertPath, "\r\n") {
return fmt.Errorf("invalid TLS CA cert path contains newline")
}

for _, key := range tlsTrustEnvKeys {
if err := os.Setenv(key, caCertPath); err != nil {
return fmt.Errorf("failed to set %s: %w", key, err)
}
}
return nil
}
46 changes: 46 additions & 0 deletions internal/cmd/proxy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -409,3 +409,49 @@ func TestClientAddr(t *testing.T) {
})
}
}

func TestConfigureTLSTrustEnvironment(t *testing.T) {
caPath := "/tmp/proxy-tls/ca.crt"

t.Run("sets trust environment variables in process", func(t *testing.T) {
assert := assert.New(t)
t.Setenv("GITHUB_ENV", "")
for _, key := range tlsTrustEnvKeys {
t.Setenv(key, "")
}

err := configureTLSTrustEnvironment(caPath)
require.NoError(t, err)

for _, key := range tlsTrustEnvKeys {
assert.Equal(caPath, os.Getenv(key), "expected %s to be set", key)
}
})

t.Run("does not rely on GITHUB_ENV", func(t *testing.T) {
assert := assert.New(t)
githubEnvFile := t.TempDir() + "/github_env"
const original = "UNCHANGED=1\n"
require.NoError(t, os.WriteFile(githubEnvFile, []byte(original), 0o644))
t.Setenv("GITHUB_ENV", githubEnvFile)
for _, key := range tlsTrustEnvKeys {
t.Setenv(key, "")
}

require.NoError(t, configureTLSTrustEnvironment(caPath))

for _, key := range tlsTrustEnvKeys {
assert.Equal(caPath, os.Getenv(key), "expected %s to be set", key)
}

content, err := os.ReadFile(githubEnvFile)
require.NoError(t, err)
assert.Equal(original, string(content))
})

t.Run("rejects CA cert path with newline", func(t *testing.T) {
err := configureTLSTrustEnvironment("/tmp/ca.crt\nMALICIOUS=1")
require.Error(t, err)
assert.Contains(t, err.Error(), "contains newline")
})
}
Loading