From f8b6b2f1f7789c069d601fe9a69e5065ad2e50e3 Mon Sep 17 00:00:00 2001 From: David Liu Date: Mon, 22 Jun 2026 14:38:03 -0400 Subject: [PATCH 1/9] Pass in enabled mTLS spec when a cert is provided --- temporalcloudcli/commands.namespace.create_test.go | 1 + temporalcloudcli/commands.namespace.go | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/temporalcloudcli/commands.namespace.create_test.go b/temporalcloudcli/commands.namespace.create_test.go index 48772d0..6b4fdce 100644 --- a/temporalcloudcli/commands.namespace.create_test.go +++ b/temporalcloudcli/commands.namespace.create_test.go @@ -93,6 +93,7 @@ func TestCreateNamespace_BuildsSpec(t *testing.T) { Lifecycle: &namespacev1.LifecycleSpec{EnableDeleteProtection: false}, Fairness: &namespacev1.FairnessSpec{TaskQueueFairnessEnabled: true}, MtlsAuth: &namespacev1.MtlsAuthSpec{ + Enabled: true, CertificateFilters: []*namespacev1.CertificateFilterSpec{ {CommonName: "test.temporal.io"}, {SubjectAlternativeName: "*.temporal.io"}, diff --git a/temporalcloudcli/commands.namespace.go b/temporalcloudcli/commands.namespace.go index 31ee48f..fc58754 100644 --- a/temporalcloudcli/commands.namespace.go +++ b/temporalcloudcli/commands.namespace.go @@ -396,12 +396,13 @@ func CreateNamespace(ctx context.Context, params CreateNamespaceParams) error { } if len(certBytes) > 0 { - spec.MtlsAuth = &namespacev1.MtlsAuthSpec{AcceptedClientCa: certBytes} + spec.MtlsAuth = &namespacev1.MtlsAuthSpec{AcceptedClientCa: certBytes, Enabled: true} } if len(certFilters) > 0 { if spec.MtlsAuth == nil { spec.MtlsAuth = &namespacev1.MtlsAuthSpec{} } + spec.MtlsAuth.Enabled = true spec.MtlsAuth.CertificateFilters = certFilters } if params.CodecEndpoint != "" { From adf5848fe2ad8f134737d7c00c723f8a3b8869a0 Mon Sep 17 00:00:00 2001 From: David Liu Date: Mon, 22 Jun 2026 14:43:34 -0400 Subject: [PATCH 2/9] missed a spot --- internal/namespace/cert.go | 4 ++-- internal/namespace/cert_test.go | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/internal/namespace/cert.go b/internal/namespace/cert.go index b4abc42..a7132b9 100644 --- a/internal/namespace/cert.go +++ b/internal/namespace/cert.go @@ -56,7 +56,7 @@ func (c *Client) AddCACerts(ctx context.Context, params AddCACertsParams) (*oper spec := ns.GetSpec() // Ensure MtlsAuth is initialized before accessing its fields if spec.MtlsAuth == nil { - spec.MtlsAuth = &namespacev1.MtlsAuthSpec{} + spec.MtlsAuth = &namespacev1.MtlsAuthSpec{Enabled: true} } spec.MtlsAuth.AcceptedClientCa = bundleBytes @@ -110,7 +110,7 @@ func (c *Client) DeleteCACerts(ctx context.Context, params DeleteCACertsParams) } else { // Ensure MtlsAuth is initialized before accessing its fields if spec.MtlsAuth == nil { - spec.MtlsAuth = &namespacev1.MtlsAuthSpec{} + spec.MtlsAuth = &namespacev1.MtlsAuthSpec{Enabled: true} } spec.MtlsAuth.AcceptedClientCa = bundleBytes } diff --git a/internal/namespace/cert_test.go b/internal/namespace/cert_test.go index bb8d938..be62252 100644 --- a/internal/namespace/cert_test.go +++ b/internal/namespace/cert_test.go @@ -67,6 +67,7 @@ func TestAddCACerts_Success(t *testing.T) { AsyncOperationId: "test-async-op", Spec: &namespacev1.NamespaceSpec{ MtlsAuth: &namespacev1.MtlsAuthSpec{ + Enabled: true, AcceptedClientCa: expectedCertBundle, }, }, @@ -123,6 +124,7 @@ func TestAddCACerts_DuplicateCertificate(t *testing.T) { ResourceVersion: "v1", Spec: &namespacev1.NamespaceSpec{ MtlsAuth: &namespacev1.MtlsAuthSpec{ + Enabled: true, AcceptedClientCa: existingCertPEM, }, }, @@ -246,6 +248,7 @@ func TestAddCACerts_CustomResourceVersion(t *testing.T) { ResourceVersion: "custom-version", Spec: &namespacev1.NamespaceSpec{ MtlsAuth: &namespacev1.MtlsAuthSpec{ + Enabled: true, AcceptedClientCa: expectedCertBundle, }, }, From 4d99c33a7e71351b4ef4e78fb166948b2b45db02 Mon Sep 17 00:00:00 2001 From: David Liu Date: Mon, 22 Jun 2026 14:44:41 -0400 Subject: [PATCH 3/9] one more --- internal/namespace/cert_filter.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/namespace/cert_filter.go b/internal/namespace/cert_filter.go index a2b232c..10f6c23 100644 --- a/internal/namespace/cert_filter.go +++ b/internal/namespace/cert_filter.go @@ -44,7 +44,7 @@ func (c *Client) AddCertFilters(ctx context.Context, params AddCertFiltersParams spec := ns.GetSpec() // Ensure MtlsAuth is initialized if spec.MtlsAuth == nil { - spec.MtlsAuth = &namespacev1.MtlsAuthSpec{} + spec.MtlsAuth = &namespacev1.MtlsAuthSpec{Enabled: true} } existingFilters := spec.MtlsAuth.GetCertificateFilters() @@ -101,7 +101,7 @@ func (c *Client) DeleteCertFilters(ctx context.Context, params DeleteCertFilters // Update the spec with the new filter list if spec.MtlsAuth == nil { - spec.MtlsAuth = &namespacev1.MtlsAuthSpec{} + spec.MtlsAuth = &namespacev1.MtlsAuthSpec{Enabled: true} } spec.MtlsAuth.CertificateFilters = newFilters From 3d61e3df5c846787c62c94d69ec4eeb6d5e78d50 Mon Sep 17 00:00:00 2001 From: David Liu Date: Mon, 22 Jun 2026 14:51:44 -0400 Subject: [PATCH 4/9] fix test --- internal/namespace/cert_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/namespace/cert_test.go b/internal/namespace/cert_test.go index be62252..4b8c601 100644 --- a/internal/namespace/cert_test.go +++ b/internal/namespace/cert_test.go @@ -40,6 +40,7 @@ func TestAddCACerts_Success(t *testing.T) { ResourceVersion: "v1", Spec: &namespacev1.NamespaceSpec{ MtlsAuth: &namespacev1.MtlsAuthSpec{ + Enabled: true, AcceptedClientCa: existingCertPEM, }, }, From 93abd77cc8886a62155f1f9332f11bd52d25362e Mon Sep 17 00:00:00 2001 From: David Liu Date: Mon, 22 Jun 2026 15:05:38 -0400 Subject: [PATCH 5/9] one more fix --- internal/namespace/cert_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal/namespace/cert_test.go b/internal/namespace/cert_test.go index 4b8c601..ebf7703 100644 --- a/internal/namespace/cert_test.go +++ b/internal/namespace/cert_test.go @@ -106,6 +106,7 @@ func TestAddCACerts_DuplicateCertificate(t *testing.T) { Spec: &namespacev1.NamespaceSpec{ MtlsAuth: &namespacev1.MtlsAuthSpec{ AcceptedClientCa: existingCertPEM, + Enabled: true, }, }, } @@ -224,6 +225,7 @@ func TestAddCACerts_CustomResourceVersion(t *testing.T) { Spec: &namespacev1.NamespaceSpec{ MtlsAuth: &namespacev1.MtlsAuthSpec{ AcceptedClientCa: existingCertPEM, + Enabled: true, }, }, } From 2a66283d8cb7a5ffba99ce1a9b3a9d3cb4a2f758 Mon Sep 17 00:00:00 2001 From: David Liu Date: Mon, 22 Jun 2026 16:48:05 -0400 Subject: [PATCH 6/9] fix test --- temporalcloudcli/commands.namespace_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/temporalcloudcli/commands.namespace_test.go b/temporalcloudcli/commands.namespace_test.go index d9bb6a1..b70930d 100644 --- a/temporalcloudcli/commands.namespace_test.go +++ b/temporalcloudcli/commands.namespace_test.go @@ -45,7 +45,6 @@ func (s *SharedServerSuite) TestNamespaceCreate() { "--name", namespaceName, "--region", "aws-ca-central-1", "--retention-days", "30", - "--api-key-auth-enabled", "--search-attribute", "MyText=Text", "--search-attribute", "MyKeyword=Keyword", "--certificate-filter", `{"commonName":"test.temporal.io","organization":"Temporal"}`, From 9612dd763a8c7da8ee3a54bdb58ee3b13b7d1c65 Mon Sep 17 00:00:00 2001 From: David Liu Date: Mon, 22 Jun 2026 16:51:07 -0400 Subject: [PATCH 7/9] test --- temporalcloudcli/commands.namespace_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/temporalcloudcli/commands.namespace_test.go b/temporalcloudcli/commands.namespace_test.go index b70930d..6b362f8 100644 --- a/temporalcloudcli/commands.namespace_test.go +++ b/temporalcloudcli/commands.namespace_test.go @@ -77,8 +77,6 @@ func (s *SharedServerSuite) TestNamespaceCreate() { s.Suite.Equal(namespaceName, gotSpec.Name) s.Suite.Equal("aws-ca-central-1", getNsRes.Namespace.ActiveRegion) s.Suite.Equal(int32(30), gotSpec.RetentionDays) - s.Suite.Require().NotNil(gotSpec.ApiKeyAuth) - s.Suite.True(gotSpec.ApiKeyAuth.Enabled) s.Suite.Equal(namespace.NamespaceSpec_SEARCH_ATTRIBUTE_TYPE_TEXT, gotSpec.SearchAttributes["MyText"]) s.Suite.Equal(namespace.NamespaceSpec_SEARCH_ATTRIBUTE_TYPE_KEYWORD, gotSpec.SearchAttributes["MyKeyword"]) @@ -158,6 +156,8 @@ func (s *SharedServerSuite) testnamespaceCRUD() { s.Suite.Equal(namespaceSpec.Regions[0], readNamespace.ActiveRegion) s.Suite.Equal(namespaceSpec.SearchAttributes, readNamespace.Spec.SearchAttributes) s.Suite.Equal(namespaceSpec.RetentionDays, readNamespace.Spec.RetentionDays) + s.Suite.Require().NotNil(readNamespace.Spec.ApiKeyAuth) + s.Suite.Equal(namespaceSpec.ApiKeyAuth.Enabled, readNamespace.Spec.ApiKeyAuth.Enabled) // get the namespace via listing res = s.Execute( From a1a1098f119d534b63a2a20fa2d197650bf05a12 Mon Sep 17 00:00:00 2001 From: David Liu Date: Mon, 22 Jun 2026 17:01:07 -0400 Subject: [PATCH 8/9] gen a cert --- temporalcloudcli/commands.namespace_test.go | 37 +++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/temporalcloudcli/commands.namespace_test.go b/temporalcloudcli/commands.namespace_test.go index 6b362f8..c8c335e 100644 --- a/temporalcloudcli/commands.namespace_test.go +++ b/temporalcloudcli/commands.namespace_test.go @@ -4,10 +4,19 @@ package temporalcloudcli_test import ( + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "crypto/x509/pkix" + "encoding/base64" "encoding/json" + "encoding/pem" "fmt" "io" + "math/big" "strings" + "testing" + "time" "github.com/temporalio/cloud-cli/temporalcloudcli" "go.temporal.io/api/temporalproto" @@ -31,11 +40,36 @@ func (s *SharedServerSuite) TestBasicNamespaceOperations() { s.cleanupNamespaces() } +// generateTestCACertBase64 generates a self-signed CA certificate and returns it as a base64-encoded PEM string. +func generateTestCACertBase64(t *testing.T) string { + t.Helper() + privateKey, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + t.Fatalf("failed to generate key: %v", err) + } + template := x509.Certificate{ + SerialNumber: big.NewInt(1), + Subject: pkix.Name{CommonName: "test.temporal.io"}, + NotBefore: time.Now(), + NotAfter: time.Now().Add(time.Hour), + KeyUsage: x509.KeyUsageCertSign, + BasicConstraintsValid: true, + IsCA: true, + } + certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &privateKey.PublicKey, privateKey) + if err != nil { + t.Fatalf("failed to create certificate: %v", err) + } + certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER}) + return base64.StdEncoding.EncodeToString(certPEM) +} + func (s *SharedServerSuite) TestNamespaceCreate() { s.cleanupNamespaces() defer s.cleanupNamespaces() namespaceName := s.generateRandomNamespaceName() + caCertBase64 := generateTestCACertBase64(s.Suite.T()) res := s.Execute( "namespace", @@ -45,6 +79,7 @@ func (s *SharedServerSuite) TestNamespaceCreate() { "--name", namespaceName, "--region", "aws-ca-central-1", "--retention-days", "30", + "--ca-certificate", caCertBase64, "--search-attribute", "MyText=Text", "--search-attribute", "MyKeyword=Keyword", "--certificate-filter", `{"commonName":"test.temporal.io","organization":"Temporal"}`, @@ -82,6 +117,8 @@ func (s *SharedServerSuite) TestNamespaceCreate() { s.Suite.Equal(namespace.NamespaceSpec_SEARCH_ATTRIBUTE_TYPE_KEYWORD, gotSpec.SearchAttributes["MyKeyword"]) s.Suite.Require().NotNil(gotSpec.MtlsAuth) + s.Suite.True(gotSpec.MtlsAuth.Enabled) + s.Suite.NotEmpty(gotSpec.MtlsAuth.AcceptedClientCa) s.Suite.Require().Len(gotSpec.MtlsAuth.CertificateFilters, 2) s.Suite.Equal("test.temporal.io", gotSpec.MtlsAuth.CertificateFilters[0].CommonName) s.Suite.Equal("Temporal", gotSpec.MtlsAuth.CertificateFilters[0].Organization) From 72e041bb26a39a13a980d0040265c83214a3d747 Mon Sep 17 00:00:00 2001 From: David Liu Date: Tue, 23 Jun 2026 14:15:47 -0400 Subject: [PATCH 9/9] empty