package dnspublish import ( "crypto/rand" "crypto/rsa" "crypto/x509" "encoding/json" "encoding/pem" "fmt" "io" "net/http" "net/http/httptest" "strings" "testing" ) // fakeGCloudServiceAccountJSON builds a syntactically valid (but not // Google-registered) service account key whose token_uri points at tokenURL — enough // for golang.org/x/oauth2/google.JWTConfigFromJSON to parse and for its JWT-signing // flow to run end-to-end against a fake local token endpoint, with no real network or // real Google credentials involved. func fakeGCloudServiceAccountJSON(t *testing.T, tokenURL string) string { t.Helper() priv, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { t.Fatal(err) } der, err := x509.MarshalPKCS8PrivateKey(priv) if err != nil { t.Fatal(err) } keyPEM := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: der}) body, err := json.Marshal(map[string]string{ "type": "service_account", "project_id": "test-project", "private_key_id": "kid1", "private_key": string(keyPEM), "client_email": "test@test-project.iam.gserviceaccount.com", "token_uri": tokenURL, }) if err != nil { t.Fatal(err) } return string(body) } func TestSetTXTRecordGCloudCreatesWhenNoneExists(t *testing.T) { var gotChangePath string var gotChangeBody map[string]any mux := http.NewServeMux() mux.HandleFunc("/token", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.Write([]byte(`{"access_token":"fake-token","token_type":"Bearer","expires_in":3600}`)) }) mux.HandleFunc("/dns/v1/projects/test-project/managedZones", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(`{"managedZones":[{"name":"my-zone","dnsName":"example.com."}]}`)) }) mux.HandleFunc("/dns/v1/projects/test-project/managedZones/my-zone/rrsets", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(`{"rrsets":[]}`)) }) mux.HandleFunc("/dns/v1/projects/test-project/managedZones/my-zone/changes", func(w http.ResponseWriter, r *http.Request) { gotChangePath = r.URL.Path body, _ := io.ReadAll(r.Body) json.Unmarshal(body, &gotChangeBody) w.Write([]byte(`{"id":"1","status":"pending"}`)) }) srv := httptest.NewServer(mux) defer srv.Close() origGCloud := GCloudAPIBase GCloudAPIBase = srv.URL defer func() { GCloudAPIBase = origGCloud }() creds := Credentials{ Provider: "gcloud", ZoneName: "example.com", GCloudProject: "test-project", GCloudServiceAccountJSON: fakeGCloudServiceAccountJSON(t, srv.URL+"/token"), } if err := SetTXTRecord(creds, "selector._domainkey.example.com", `"v=DKIM1; k=rsa; p=abc"`); err != nil { t.Fatal(err) } if gotChangePath == "" { t.Fatal("expected a Changes.Create request, got none") } additions, _ := gotChangeBody["additions"].([]any) if len(additions) != 1 { t.Fatalf("expected exactly one addition, got %v", gotChangeBody) } added := additions[0].(map[string]any) if added["name"] != "selector._domainkey.example.com." || fmt.Sprint(added["rrdatas"]) != "[\"v=DKIM1; k=rsa; p=abc\"]" { t.Fatalf("unexpected addition: %+v", added) } if deletions, ok := gotChangeBody["deletions"]; ok && deletions != nil { if arr, ok := deletions.([]any); ok && len(arr) != 0 { t.Fatalf("expected no deletions when no record existed, got %v", deletions) } } } func TestSetTXTRecordGCloudNoZoneFound(t *testing.T) { mux := http.NewServeMux() mux.HandleFunc("/token", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(`{"access_token":"fake-token","token_type":"Bearer","expires_in":3600}`)) }) mux.HandleFunc("/dns/v1/projects/test-project/managedZones", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(`{"managedZones":[]}`)) }) srv := httptest.NewServer(mux) defer srv.Close() orig := GCloudAPIBase GCloudAPIBase = srv.URL defer func() { GCloudAPIBase = orig }() creds := Credentials{ Provider: "gcloud", ZoneName: "nope.example", GCloudProject: "test-project", GCloudServiceAccountJSON: fakeGCloudServiceAccountJSON(t, srv.URL+"/token"), } err := SetTXTRecord(creds, "selector._domainkey.nope.example", `"v=DKIM1"`) if err == nil { t.Fatal("expected an error when no managed zone matches") } if !strings.Contains(err.Error(), "no managed zone found") { t.Fatalf("unexpected error: %v", err) } }