WriteHostCAFile writes the MITM CA cert to ~/.agent-vault/isolation/ca- .pem with mode 0o644 (the container's unprivileged claude user must read it via the bind mount). The enclosing directory stays 0o700 so only the host user and root can read the file on the host side. Returns the full
(pem []byte, sessionID string)
| 30 | // |
| 31 | // Returns the full host path for use as a docker -v source. |
| 32 | func WriteHostCAFile(pem []byte, sessionID string) (string, error) { |
| 33 | if !sessionIDRE.MatchString(sessionID) { |
| 34 | return "", fmt.Errorf("WriteHostCAFile: sessionID must be hex, got %q", sessionID) |
| 35 | } |
| 36 | dir, err := hostIsolationDir() |
| 37 | if err != nil { |
| 38 | return "", err |
| 39 | } |
| 40 | if err := os.MkdirAll(dir, 0o700); err != nil { |
| 41 | return "", fmt.Errorf("create isolation dir: %w", err) |
| 42 | } |
| 43 | path := filepath.Join(dir, caPrefix+sessionID+caSuffix) |
| 44 | if err := os.WriteFile(path, pem, 0o600); err != nil { |
| 45 | return "", fmt.Errorf("write CA file: %w", err) |
| 46 | } |
| 47 | // WriteFile with 0o600 is default-safe; Chmod to 0o644 is the |
| 48 | // explicit step that lets the container read its own bind mount. |
| 49 | // Parent dir is 0o700 so the host attack surface is unchanged. |
| 50 | if err := os.Chmod(path, 0o644); err != nil { // #nosec G302 -- container user (UID != host) must read bind-mounted CA; parent dir is 0o700 |
| 51 | return "", fmt.Errorf("chmod CA file: %w", err) |
| 52 | } |
| 53 | return path, nil |
| 54 | } |
| 55 | |
| 56 | // PruneHostCAFiles removes ca-*.pem files in ~/.agent-vault/isolation/ |
| 57 | // older than caStaleTTL. Best-effort — errors are ignored because this |