Files
at-container-registry/cmd/credential-helper/cmd_configure.go
T

160 lines
3.6 KiB
Go

package main
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"strings"
"github.com/charmbracelet/huh"
"github.com/spf13/cobra"
)
func newConfigureDockerCmd() *cobra.Command {
return &cobra.Command{
Use: "configure-docker",
Short: "Configure Docker to use this credential helper",
Long: "Adds or updates the credHelpers entry in ~/.docker/config.json\nfor all configured registries.",
RunE: runConfigureDocker,
}
}
func runConfigureDocker(cmd *cobra.Command, args []string) error {
cfg, err := loadConfig()
if err != nil {
return fmt.Errorf("loading config: %w", err)
}
if len(cfg.Registries) == 0 {
fmt.Fprintf(os.Stderr, "No registries configured.\n")
fmt.Fprintf(os.Stderr, "Run: docker-credential-atcr login\n")
return nil
}
// Collect registry hosts
var hosts []string
for url := range cfg.Registries {
host := strings.TrimPrefix(url, "https://")
host = strings.TrimPrefix(host, "http://")
hosts = append(hosts, host)
}
dockerConfigPath := getDockerConfigPath()
// Load existing Docker config
dockerCfg := loadDockerConfig()
if dockerCfg == nil {
dockerCfg = make(map[string]any)
}
// Get or create credHelpers
helpers, ok := dockerCfg["credHelpers"]
if !ok {
helpers = make(map[string]any)
}
helpersMap, ok := helpers.(map[string]any)
if !ok {
helpersMap = make(map[string]any)
}
// Check what needs to change
var toAdd []string
for _, host := range hosts {
current, exists := helpersMap[host]
if !exists || current != "atcr" {
toAdd = append(toAdd, host)
}
}
if len(toAdd) == 0 {
fmt.Printf("Docker is already configured for all registries.\n")
return nil
}
fmt.Printf("Will update %s:\n", dockerConfigPath)
for _, host := range toAdd {
fmt.Printf(" + credHelpers[%q] = \"atcr\"\n", host)
}
fmt.Println()
var confirm bool
err = huh.NewConfirm().
Title("Apply changes?").
Value(&confirm).
Run()
if err != nil || !confirm {
fmt.Fprintf(os.Stderr, "Cancelled.\n")
return nil
}
// Apply changes
for _, host := range toAdd {
helpersMap[host] = "atcr"
}
dockerCfg["credHelpers"] = helpersMap
// Remove conflicting credsStore if it exists and we're adding credHelpers
if _, hasStore := dockerCfg["credsStore"]; hasStore {
fmt.Fprintf(os.Stderr, "Note: credsStore is set — credHelpers takes precedence for configured registries.\n")
}
if err := saveDockerConfig(dockerConfigPath, dockerCfg); err != nil {
return fmt.Errorf("saving Docker config: %w", err)
}
fmt.Printf("Docker configured successfully.\n")
return nil
}
// getDockerConfigPath returns the path to Docker's config.json
func getDockerConfigPath() string {
// Check DOCKER_CONFIG env var first
if dir := os.Getenv("DOCKER_CONFIG"); dir != "" {
return filepath.Join(dir, "config.json")
}
homeDir, err := os.UserHomeDir()
if err != nil {
return ""
}
return filepath.Join(homeDir, ".docker", "config.json")
}
// loadDockerConfig loads Docker's config.json as a generic map
func loadDockerConfig() map[string]any {
path := getDockerConfigPath()
if path == "" {
return nil
}
data, err := os.ReadFile(path)
if err != nil {
return nil
}
var config map[string]any
if err := json.Unmarshal(data, &config); err != nil {
return nil
}
return config
}
// saveDockerConfig writes Docker's config.json
func saveDockerConfig(path string, config map[string]any) error {
// Ensure directory exists
dir := filepath.Dir(path)
if err := os.MkdirAll(dir, 0700); err != nil {
return err
}
data, err := json.MarshalIndent(config, "", "\t")
if err != nil {
return err
}
data = append(data, '\n')
return os.WriteFile(path, data, 0600)
}