cmd/xb: update to be able to push with podman

When running in rootless podman we need to do the docker
authentication right before, and then also disable
CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE
(see b/545416868).

Change-Id: Ie7237864ebe6a1fdc9a194613ad0649e6a6a6964
Reviewed-on: https://go-review.googlesource.com/c/build/+/854045
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Michael Matloob <matloob@google.com>
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
diff --git a/cmd/xb/xb.go b/cmd/xb/xb.go
index ba8293d..5c38b90 100644
--- a/cmd/xb/xb.go
+++ b/cmd/xb/xb.go
@@ -154,7 +154,23 @@
 		}
 	}
 
-	runCmd()
+	var extraEnv []string
+	if flag.Arg(0) == "podman" && flag.Arg(1) == "push" {
+		// When rootless podman invokes docker-credential-gcloud, it runs inside
+		// podman's user namespace where gcloud's Enterprise Certificate Proxy (ECP)
+		// cannot access the host PKCS#11 socket. Refresh the token on the host first
+		// (where ECP works), then disable client certificates for the podman push
+		// invocation so docker-credential-gcloud uses the cached token without starting ECP.
+		helper := exec.Command("gcloud", "auth", "docker-helper", "get")
+		helper.Stdin = strings.NewReader("https://gcr.io\n")
+		helper.Stderr = os.Stderr
+		if b, err := helper.Output(); err != nil {
+			log.Fatalf("refreshing gcloud docker-helper token: %v\ncommand stdout: %q", err, b)
+		}
+		extraEnv = append(extraEnv, "CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE=false")
+	}
+
+	runCmd(extraEnv...)
 }
 
 // fromLayers returns the layers named in the provided Dockerfile
@@ -182,8 +198,9 @@
 	return
 }
 
-func runCmd() {
+func runCmd(extraEnv ...string) {
 	cmd := exec.Command(flag.Arg(0), flag.Args()[1:]...)
+	envutil.SetEnv(cmd, extraEnv...)
 	cmd.Stdout = os.Stdout
 	cmd.Stderr = os.Stderr
 	err := cmd.Run()